《MySQL高级篇》六、索引的创建与设计原则(二)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: 《MySQL高级篇》六、索引的创建与设计原则

2. 使用 CREATE INDEX 创建索引

CREATE INDEX 语句可以在已经存在的表上添加索引,在 MySQL 中, CREATE INDEX 被映射到一个 ALTER TABLE 语句上,基本语法结构为:

CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name
ON table_name (col_name[length],...) [ASC | DESC]

举例1:在book表的comment字段上建立名为 的普通索引

create index idx_cmt on book(comment);

举例2:在book表中的book_id字段上建立名为uk_idx_bid的唯一索引,SQL语句如下:

CREATE UNIQUE INDEX uk_idx_bid ON book(book_id);

举例3:在book表的book_id、book_name、info字段上建立联合索引,SQL语句如下:

CREATE INDEX mul_bid_bname_info ON book(book_id,book_name,info);

1.3 删除索引

MySQL中删除索引使用ALTER TABLEDROP INDEX语句,两者可实现相同的功能,DROP INDEX语句在内部被映射到一个ALTER TABLE语句中

1. 使用 ALTER TABLE 删除索引:

ALTER TABLE删除索引的基本语法格式如下:

ALTER TABLE table_name DROP INDEX index_name;


练习:删除book表中名称为idx_bk_id的唯一索引

首先查看book表中是否名称为idx_bk_id的索引,输入SHOW语句如下:

SHOW INDEX FROM book\G;


下面删除该索引,输入删除语句如下:

ALTER TABLE book DROP INDEX idx_bk_id;


提示

添加AUTO_INCREMENT约束字段的唯一索引不能被删除()

2. 使用 DROP INDEX 语句删除索引:


DROP INDEX删除索引的基本语法格式如下:

DROP INDEX index_name ON table_name;

练习:删除book表中名称为idx_aut_info的组合索引,SQL语句如下:

DROP INDEX idx_aut_info ON book;


语句执行完毕,使用SHOW查看索引是否删除:

SHOW CREATE TABLE book\G;

可以看到,book表中已经没有名称为idx_aut_info的组合索引,删除索引成功。

提示 删除表中的列时,如果要删除的列为索引的组成部分,则该列也会从索引中删除。如果组成索引的所有列都被删除,则整个索引将被删除。


2. MySQL 8.0 索引新特性

2.1 支持降序索引

1b685ad278bf01fc70365c2abbc742fa.png


举例:分别在 MySQL 5.7 版本和 MySQL 8.0 版本中创建数据表 ts1,结果如下:

CREATE TABLE ts1(a int,b int,index idx_a_b(a,b desc));

在 MySQL 5.7 版本中查看数据表 ts1 的结构,结果如下:

6dc922145802e6f761388ccfb4947706.png

从结果可以看出,索引仍然是默认的升序

在MySQL 8.0版本中查看数据表ts1的结构,结果如下:

f6104b02e5a9d1de6d368a30da4aae19.png

从结果可以看出,索引已经是降序了。下面继续测试降序索引在执行计划中的表现。

分别在 MySQL 5.7 版本和 MySQL 8.0 版本的数据表 ts1 中插入 800 条随机数据,执行语句如下:

DELIMITER //
CREATE PROCEDURE ts_insert()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i < 800
    DO
        insert into ts1 select rand()*80000,rand()*80000;
        SET i = i + 1;
    END WHILE;
    commit;
END //
DELIMITER ; 
#调用
CALL ts_insert();

在 MySQL 5.7 版本中查看数据表 ts1 的执行计划,结果如下:

# 优化测试
EXPLAIN SELECT * FROM ts1 ORDER BY a,b DESC LIMIT 5;

0dbaa6f2fcdf3d2ba67bd7a9f5f395c2.png

从结果可以看出,执行计划中扫描数为 799,而且使用了 Using filesort。


提示:Using filesort 是MySQL中一种速度比较慢的外部排序,能避免是最好的。多数情况下,管理员可以通过优化索引来尽量避免出现 Using filesort,从而提高数据库执行速度。


在 MySQL 8.0 版本中查看数据表 ts1 的执行计划


97d5517eb88458e2eaa115a51f010ff6.png

从结果可以看出,执行计划中扫描数为 5,而且没有使用 Using filesort。


注意:降序索引只对查询中特定的排序顺序有效,如果使用不当,反而查询效率更低。例如,上述查询排序条件改为 order by a desc, b desc,MySQL 5.7 的执行计划要明显好于 MySQL 8.0。


将排序条件改为order by a desc,b desc后,下面来对比不同版本中执行计划的效果。


在MySQL5.7版本中查看数据表ts1的执行计划,结果如下:

# 优化测试
EXPLAIN SELECT * FROM ts1 ORDER BY a DESC,b DESC LIMIT 5;

f4b9b3e7bcb0126d8d25254735bf9b1f.png


在 MySQL 8.0 版本中查看数据表 ts1 的执行计划

4a3b520b14544b9a32edff054a52f73f.png


从结果可以看出,修改后MySQL5.7的执行计划明显好于MySQL8.0

2.2 隐藏索引(invisible indexes)


在 MySQL 5.7 版本及之前,只能通过显式的方式删除索引。此时,如果发现删除索引后出现错误,又只能通过显式创建索引的方式将删除的索引创建回来。如果数据表中的数据量非常大,或者数据表本身比较大,这种操作就会消耗系统过多的资源,操作成本非常高。


从MySQL 8.x 开始支持 隐藏索引(invisible indexes),只需要将待删除的索引设置为隐藏索引,使查询优化器不再使用这个索引(即使使用 force index(强制使用索引),优化器也不会使用该索引), 确认将索引设置为隐藏索引后系统不受任何响应,就可以彻底删除索引。这种通过先将索引设置为隐藏索引,再删除索引的方式就是软删除。


431e41486bd10b658a7c459884c581cb.png


1. 创建表时直接创建


在 MySQL 中创建隐藏索引通过 SQL 语句 INVISIBLE 来实现,其语法形式如下:


 CREATE TABLE tablename(
    propname1 type1[CONSTRAINT1],
    propname2 type2[CONSTRAINT2],
    ......
    propnamen typen,
    INDEX [indexname](propname1 [(length)]) INVISIBLE
);

上述语句比普通索引多了一个关键字 INVISIBLE,用来标记索引为不可见索引。

练习:在创建书籍表book时,在字段idx_cmt上创建隐藏索引

#① 创建表时,隐藏索引
create table book(
    book_id INT,
    book_name VARCHAR(100),
    AUTHORS VARCHAR (100),
    info VARCHAR (100),
    COMMENT VARCHAR (100),
    year_publication YEAR,
    # 创建不可见的索引
    index idx_cmt(comment) invisible
);

通过explain查看发现,优化器并没有使用索引,而是使用的全表扫描

explain select * from book7 where comment = 'mysql...';


9764509ea019809eee9673dd37fc1382.png


2. 在已经存在的表上创建

可以为已经存在的表设置隐藏索引,其语法形式如下:

CREATE INDEX indexname
ON tablename(propname[(length)]) INVISIBLE;

举例:

CREATE INDEX idx_year_pub ON book(year_publication) INVISIBLE;


3. 通过 ALTER TABLE 语句创建

语法形式如下:

ALTER TABLE tablename
ADD INDEX indexname (propname [(length)]) INVISIBLE;


举例:

ALTER TABLE book
ADD UNIQUE INDEX uk_idx_bname(book_name) INVISIBLE;

4. 切换索引可见状态

已存在的索引可通过如下语句切换可见状态:

 ALTER TABLE tablename ALTER INDEX index_name INVISIBLE; #切换成隐藏索引 
 ALTER TABLE tablename ALTER INDEX index_name VISIBLE; #切换成非隐藏索引

举例:

# 修改索引的可见性
ALTER TABLE book ALTER INDEX idx_year_pub invisible;#可见--->不可见
ALTER TABLE book ALTER INDEX idx_cmt visible;#不可见---》可见

如果将 idx_cmt 索引切换成可见状态,通过 explain 查看执行计划,发现优化器选择了idx_cmt索引

image.png

**注意:**当索引被隐藏时,它的内容仍然是和正常索引一样实时更新的。如果一个索引需要长期被隐藏,那么可以将其删除,因为索引的存在会影响插入、更新和删除的性能。

通过设置隐藏索引的可见性可以查看索引对调优的帮助。

5. 使隐藏索引对查询优化器可见(了解)

在 MySQL 8.x 版本中,为索引提供了一种新的测试方式,可以通过查询优化器的一个开关 (use_invisible_indexes)来打开某个设置,使隐藏索引对查询优化器可见。如果 use_invisible_indexes 设置为 off(默认),优化器会忽略隐藏索引。如果设置为 on,即使隐藏索引不可见,优化器在生成执行计划时仍会考虑使用隐藏索引。


(1)在 MySQL 命令行执行如下命令查看查询优化器的开关设置。

mysql> select @@optimizer_switch \G

在输出的结果信息中找到如下属性配置。

use_invisible_indexes=off

此属性配置值为off,说明隐藏索引默认对查询优化器不可见。


(2)使隐藏索引对查询优化器可见,需要在 MySQL 命令行执行如下命令:


mysql> set session optimizer_switch="use_invisible_indexes=on";
Query OK, 0 rows affected (0.00 sec)

SQL 语句执行成功,再次查看查询优化器的开关设置。

mysql>  select @@optimizer_switch \G
*************************** 1. row ***************************
@@optimizer_switch:
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_
intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_co
st_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on
,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on
,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_ind
exes=on,skip_scan=on,hash_join=on
1 row in set (0.00 sec)

此时,在输出结果中可以看到如下属性配置。

use_invisible_indexes=on

use_invisible_indexes 属性的值为 on,说明此时隐藏索引对查询优化器可见。


(3)使用 EXPLAIN 查看以字段 invisible_column 作为查询条件时的索引使用情况。


explain select * from classes where cname = '高一2班';

查询优化器会使用隐藏索引来查询数据。

(4)如果需要使隐藏索引对查询优化器不可见,则只需要执行如下命令即可。

mysql> set session optimizer_switch="use_invisible_indexes=off";
Query OK, 0 rows affected (0.00 sec)

再次查看查询优化器的开关设置。

mysql> select @@optimizer_switch \G;


此时,use_invisible_indexes 属性的值已经被设置为“off


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
14 4
|
3天前
|
SQL JavaScript 关系型数据库
Mysql索引不当引发死锁问题
本文通过真实案例解析了MySQL在高并发环境下出现死锁的问题。数据库表`t_award`包含多个索引,但在执行特定SQL语句时遭遇索引失效,导致更新操作变慢并引发死锁。分析发现,联合索引`(pool_id, identifier, status, is_redeemed)`因`identifier`允许为空值而导致索引部分失效。此外,`pool_id`上的普通索引产生的间隙锁在高并发下加剧了死锁风险。为解决此问题,文中提出了调整索引顺序至`(pool_id, status, is_redeemed, identifier)`等方案来优化索引使用,进而减轻死锁现象。
|
6天前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
19天前
|
存储 SQL 关系型数据库
(六)MySQL索引原理篇:深入数据库底层揭开索引机制的神秘面纱!
《索引原理篇》它现在终于来了!但对于索引原理及底层实现,相信大家多多少少都有了解过,毕竟这也是面试过程中出现次数较为频繁的一个技术点。在本文中就来一窥`MySQL`索引底层的神秘面纱!
|
19天前
|
SQL 存储 关系型数据库
(五)MySQL索引应用篇:建立索引的正确姿势与使用索引的最佳指南!
在本篇中,则重点讲解索引应用相关的方式方法,例如各索引优劣分析、建立索引的原则、使用索引的指南以及索引失效与索引优化等内容。
|
13天前
|
缓存 关系型数据库 MySQL
MySQL调优秘籍曝光!从索引到事务,全方位解锁高可用秘诀,让你的数据库性能飞起来!
【8月更文挑战第6天】MySQL是顶级关系型数据库之一,其性能直接影响应用的高可用性与用户体验。本文聚焦MySQL的高性能调优,从索引设计到事务管理,逐一解析。介绍如何构建高效索引,如联合索引`CREATE INDEX idx_order_customer ON orders(order_id, customer_id);`,以及索引覆盖查询等技术。
39 0
|
19天前
|
存储 SQL 关系型数据库
(四)MySQL之索引初识篇:索引机制、索引分类、索引使用与管理综述
本篇中就对MySQL的索引机制有了全面认知,从索引的由来,到索引概述、索引管理、索引分类、唯一/全文/联合/空间索引的创建与使用等内容,进行了全面概述。
|
23天前
|
存储 数据挖掘 BI
数据仓库深度解析与实时数仓应用案例探析
随着数据量的不断增长和数据应用的广泛深入,数据治理和隐私保护将成为数据仓库建设的重要议题。企业需要建立完善的数据治理体系,确保数据的准确性、一致性和完整性;同时加强隐私保护机制建设,确保敏感数据的安全性和合规性。
128 55
|
6天前
|
消息中间件 存储 大数据
大数据-数据仓库-实时数仓架构分析
大数据-数据仓库-实时数仓架构分析
22 1
|
23天前
|
存储 消息中间件 数据挖掘
数据仓库的深度探索与实时数仓应用案例解析
大数据技术的发展,使得数据仓库能够支持大量和复杂数据类型(如文本、图像、视频、音频等)。数据湖作为一种新的数据存储架构,强调原始数据的全面保留和灵活访问,与数据仓库形成互补,共同支持企业的数据分析需求。

热门文章

最新文章