新特性解读 | MySQL 8.0 索引特性4-不可见索引

原创: 杨涛涛mysql


MySQL 8.0 实现了索引的隐藏属性。固然这个特性不少商业数据库早就有了,好比ORACLE,在11g中就实现了。我来介绍下这个小特性。sql

 

介绍

INVISIBLE INDEX,不可见索引或者叫隐藏索引。就是对优化器不可见,查询的时候优化器不会把她做为备选。数据库

其实之前要想完全不可见,只能用开销较大的drop index;如今有了新的方式,能够改变索引的属性,让其不可见,这一操做只更改metadata,开销很是小。测试

 

使用场景

我大概描述下有可能使用隐藏索引的场景:优化

1. 好比,我有张表t1,原本已经有索引idxf1,idxf2,idxf3。我经过数据字典检索到idxf3基本没有使用过,那我是否是能够判断这个索引直接删掉就行了?那若是删掉后忽然有新上的业务要大量使用呢?难道我要频繁的drop index/add index吗?这个时候选择开销比较小的隐藏索引就行了。spa

2. 个人业务只有一个可能每月固定执行一次的SQL用到这个索引,那选择隐藏索引太合适不过了。code

3. 又或者是我想要测试下新建索引对我整个业务的影响程度。若是我直接建新索引,那我既有业务涉及到这个字段的有可能会收到很大影响。那这个时候隐藏索引也是很是合适的。索引

 

举例

下面我来简单举例如何使用隐藏索引:ci

表结构it

mysql> create table f1 (id serial primary key, f1 int,f2 int );
Query OK, 0 rows affected (0.11 sec)

建立两个索引,默承认见。

索引1,

mysql> alter table f1 add key idx_f1(f1), add key idx_f2(f2);
Query OK, 0 rows affected (0.12 sec)
Records: 0 Duplicates: 0 Warnings: 0

索引2,

mysql> show create table f1\G
*************************** 1. row ***************************
Table: f1
Create Table: CREATE TABLE `f1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`f1` int(11) DEFAULT NULL,
`f2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `idx_f1` (`f1`),
KEY `idx_f2` (`f2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

简单写个造数据的存储过程。

DELIMITER $$
USE `ytt`$$
CREATE PROCEDURE `sp_generate_data_f1`(
IN f_cnt INT
)
BEGIN
DECLARE i,j INT DEFAULT 0;
SET @@autocommit=0;
WHILE i < f_cnt DO
SET i = i + 1;
IF j = 100 THEN
SET j = 0;
COMMIT;
END IF;
SET j = j + 1;
INSERT INTO f1 (f1,f2) SELECT CEIL(RAND()*100),CEIL(RAND()*100);
END WHILE;
COMMIT;
SET @@autocommit=1;
END$$
DELIMITER ;

生成1W条记录

mysql> call sp_generate_data_f1(10000);
Query OK, 0 rows affected (5.42 sec)

咱们把f2列上的索引变为不可见,结果瞬间完成。

mysql> alter table f1 alter index idx_f2 invisible;
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0

在看下表结构,此时索引标记为Invisible。

mysql> show create table f1 \G
*************************** 1. row ***************************
Table: f1
Create Table: CREATE TABLE `f1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`f1` int(11) DEFAULT NULL,
`f2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `idx_f1` (`f1`),
KEY `idx_f2` (`f2`) /*!80000 INVISIBLE */
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

给一条有f2列过滤的SQL, 发现优化器用不到这个索引了。

mysql> explain select count(*) from f1 where f2 = 52\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: f1
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 9991
filtered: 1.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

用force index 强制使用,直接报错。

mysql> explain select count(*) from f1 force index (idx_f2) where f2 = 52\G
ERROR 1176 (42000): Key 'idx_f2' doesn't exist in table 'f1'

那 MySQL 8.0 的优化器开关里能够告诉它,有的时候能够用隐藏索引。来打开看看。

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

那这条SQL 如今能够用idx_f2了。

mysql> explain select count(*) from f1 where f2 = 52\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: f1
partitions: NULL
type: ref
possible_keys: idx_f2
key: idx_f2
key_len: 5
ref: const
rows: 121
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.00 sec)

 

总结

INVISIBLE INDEX 的确是一个颇有用的小特性,给索引增长了第三个额外的开关选项。想要了解更多的建议阅读MySQL手册。

相关文章
相关标签/搜索