MySQL 8.0 虽然发布好久了,但可能你们都停留在 5.7.x,甚至更老,其实 MySQL 8.0 新增了许多重磅新特性,好比栈长今天要介绍的 "隐藏索引" 或者 "不可见索引"。html
隐藏索引 字面意思就是把索引进行隐藏,即不可见,它不是用来查询优化的,因此它不会被优化器使用到。隐藏索引适用于除主键索引(显示或者隐式设置)以外的索引,意味着主键索引是不能经过任何方式隐藏的。java
MySQL 数据库默认建立的索引都是可见的,要显式控制一个索引的可见性,能够在 CREATE TABLE,CREATE INDEX 或 ALTER TABLE 的索引定义命令中使用 VISIBLE
或 INVISIBLE
关键字。mysql
以下面示例所示:面试
CREATE TABLE javastack ( age INT, weight INT, tall INT, INDEX age_idx (age) INVISIBLE ) ENGINE = InnoDB; CREATE INDEX weight_idx ON javastack (weight) INVISIBLE; ALTER TABLE javastack ADD INDEX tall_idx (tall) INVISIBLE;
要变动现有索引的可见性,能够在 ALTER TABLE ... ALTER INDEX 命令中使用 VISIBLE
或 INVISIBLE
关键字。spring
年龄索引变动为不可见(隐藏):sql
ALTER TABLE javastack ALTER INDEX age_idx INVISIBLE;
年龄索引变动为可见:数据库
ALTER TABLE javastack ALTER INDEX age_idx VISIBLE;
怎么知道一个表中的索引是可见仍是不可见,能够从 INFORMATION_SCHEMA.STATISTICS 表,或者 SHOW INDEX 命令输出中得到。例如:intellij-idea
mysql> SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 'javastack'; +------------+------------+ | INDEX_NAME | IS_VISIBLE | +------------+------------+ | age_idx | YES | | weight_idx | NO | | tall_idx | NO | +------------+------------+
从上面隐藏索引介绍咱们知道,隐藏索引能够不被优化器所使用,那么咱们能够把某个表的某个索引设置隐藏,而后再测试 SQL 语句的查询性能。ide
便可以利用隐藏索引快速测试删除索引后对 SQL 查询性能的影响,而无需进行索引删除、重建操做,若是须要该索引,再设置可见就行了,这在大表测试中无疑很是有用,由于对于大表索引的删除和从新添加很耗性能,甚至影响表的正常工做。spring-boot
若是一个索引被设置成隐藏了,但实际上又须要被优化器所使用,有几种表索引状况缺失对查询形成的影响:
1)SQL 查询语句中包含了索引提示指向不可见索引会发生错误;
2)性能模式数据中显示了受影响 SQL 查询语句的负载增高;
3)SQL 查询语句进行 EXPLIAN 时出现了不一样的执行计划;
4)SQL 查询语句出如今了慢查询日志中(以前没有出现);
系统变量 optimizer_switch 的 use_invisible_indexes 标志的值,控制了优化器执行计划构建时是否使用隐藏索引。
若是 use_invisible_indexes 值设置为 off 关闭状态(默认值),优化器默认会忽略隐藏索引,即和加入该参数以前的效果同样。
若是 use_invisible_indexes 值设置为 on 打开状态,隐藏索引仍然保持不可见,但优化器会把隐藏索引加入到执行计划的构建中。
若是想要在某条单个 SQL 查询语句上启用隐藏索引,可使用 SET_VAR 优化器提示来临时更新 optimizer_switch 的值,以下所示:
mysql> EXPLAIN SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ > age, weight FROM javastack WHERE weight >= 150\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: javastack partitions: NULL type: range possible_keys: weight_idx key: weight_idx key_len: 5 ref: NULL rows: 2 filtered: 100.00 Extra: Using index condition mysql> EXPLAIN SELECT age, weight FROM javastack WHERE weight >= 150\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: javastack partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 5 filtered: 33.33 Extra: Using where
索引的可见性不会影响索引的自身维护,例如,无论索引是可见仍是不可见,每次表数据行的更改索引都会更新,而且惟一索引也可防止插入重复数据。
没有显式主键的表若是在 NOT NULL 列上有任何一个惟一索引,则仍可能成为有效的隐式主键。在这种状况下,第一个这样的索引会对表数据行施加与显式主键相同的约束,而且该索引不能设置为不可见。
如如下表的定义:
CREATE TABLE javastack ( age INT NOT NULL, weight INT NOT NULL, UNIQUE weight_idx (weight) ) ENGINE = InnoDB;
该表定义不包含任何显式主键,可是 weight 列为 NOT NULL,在该列上建立的惟一索引在数据行上与主键具备相同的约束,而且不能使其不可见:
mysql> ALTER TABLE javastack ALTER INDEX weight_idx INVISIBLE; ERROR 3522 (HY000): A primary key index cannot be invisible.
假设如今咱们将一个显式主键添加到表中:
ALTER TABLE javastack ADD PRIMARY KEY (age);
显式主键不能设置为不可见,此时,weight 列上的惟一索引再也不充当隐式主键,所以可使其设置不可见。
mysql> ALTER TABLE javastack ALTER INDEX weight_idx INVISIBLE; Query OK, 0 rows affected (0.03 sec)
本文介绍了 MySQL 8.0 中的新特性:隐藏(不可见)索引,这个索引并非新加的索引类型,而是能够控制索引是否加入到执行计划的构建之中。
在实际生产中也能够利用隐藏索引进行 SQL 语句的性能测试,或者对索引进行逻辑删除,以及索引的灰度发布测试等,用处仍是蛮大的。
本次的分享就到这里了,但愿对你们有用。以为不错,在看、转发分享一下哦~
最后,MySQL 系列教程还会继续更新,关注Java技术栈公众号第一时间推送,还能够在公众号菜单中获取历史 MySQL 教程,都是干货。
参考文档:
https://dev.mysql.com/doc/ref...
话说大家用的 MySQL 哪一个版本呢?来投票一下!
另外,关注公众号Java技术栈,在后台回复:面试,能够获取我整理的 MySQL 系列面试题和答案,很是齐全。
版权申明:本文系公众号 "Java技术栈" 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重他人劳动成果和知识产权。
近期热文推荐:
1.Java 15 正式发布, 14 个新特性,刷新你的认知!!
2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!
3.我用 Java 8 写了一段逻辑,同事直呼看不懂,你试试看。。
以为不错,别忘了随手点赞+转发哦!