MySQL 8.0 版本支持不可见索引(Invisible Indexes),也就是索引对优化器不可见,无法使用不可见索引对查询进行优化,不可见索引不适用于主键。
一、不可见索引的使用场景
在一张大表上创建和删除索引是有高额成本的,有时候需要测试一个索引是否有效,可以临时删除索引,对比索引存在与否,对查询的性能影响。使用索引不可见的特性,就能避免索引被真正删除,在需要的时候,把索引设置为可见即可,避免了索引真正删除和创建带来的影响。
二、不可见索引语法
默认情况下,索引都是可见的,可以使用下面的关键字来指定索引的可见性。
- VISIBLE
- INVISIBLE
在创建表,创建索引,修改索引的语句中,使用上述关键字,指定索引的可见性,示例如下:
# 创建表
CREATE TABLE t1 (
i INT,
j INT,
k INT,
INDEX i_idx (i) INVISIBLE
) ENGINE = InnoDB;
# 创建索引
CREATE INDEX j_idx ON t1 (j) INVISIBLE;
# 增加索引
ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;
如果想修改一个索引的可见性,使用如下语法:
ALTER TABLE t1 ALTER INDEX i_idx INVISIBLE;
ALTER TABLE t1 ALTER INDEX i_idx VISIBLE;
三、查询索引的可见性
通常使用 NFORMATION_SCHEMA.STATISTICS 表或者 show index from xxx 语法来查询表中索引的可见性,如下:
mysql> SELECT INDEX_NAME, IS_VISIBLE
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 't1';
+------------+------------+
| INDEX_NAME | IS_VISIBLE |
+------------+------------+
| i_idx | YES |
| j_idx | NO |
| k_idx | NO |
+------------+------------+
mysql> show index from sbtest1\G
*************************** 1. row ***************************
Table: sbtest1
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 985302
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
*************************** 2. row ***************************
Table: sbtest1
Non_unique: 1
Key_name: k_1
Seq_in_index: 1
Column_name: k
Collation: A
Cardinality: 158371
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
2 rows in set (0.01 sec)
四、不可见索引注意事项
在优化器参数 optimizer_switch 有一个选项 use_invisible_indexes 来控制优化器是否可以使用不可见索引,该选项默认为 off,即默认情况下,不能使用不可见索引。如果该选项设置为 on,不可见索引仍然保持不可见,但是优化器在构建执行计划时,将该索引考虑在内。
不可见索引不影响该索引的维护,比如数据更新,不可见索引同样也会更新,不可见的唯一索引,同样可以阻止相同值的插入。
隐式的非空唯一索引作为表的主键,该唯一索引不能设置为不可见,除非添加一个显式的主键,然后该唯一索引就可以设置为不可见,示例如下:
CREATE TABLE t2 (
i INT NOT NULL,
j INT NOT NULL,
UNIQUE j_idx (j)
) ENGINE = InnoDB;
mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;
ERROR 3522 (HY000): A primary key index cannot be invisible.
ALTER TABLE t2 ADD PRIMARY KEY (i);
mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;
Query OK, 0 rows affected (0.03 sec)