在8.0中新增了三种索引类型:隐藏索引、降序索引、函数索引
1、隐藏索引:
含义:mysq8.0开始支持隐藏索引,不可见索引。
特点:不会被优化器所使用,但仍然需要进行维护。
应用场景:软删除、灰度发布。
软删除: 需要进行索引的删除时,现在只能删除后查看效果,但是删除后发现索引不应该被删除,那只能再创建出来,这个过程是非常耗性能的。这时我们可以使用隐藏索引,先设置为隐藏,等确认删除没有影响之后再进行真正的删除。
使用:
创建隐藏索引的关键字是invisible, 在正常创建索引的最后加上invisible字段即可。
这里我们完整的创建一张表,
create table test_hidden_index(i int, j int); // 创建一张表,表里有 i 和 j 两个字段
create index idx_i on test_hidden_index(i); // 创建一个正常的索引
create index idx_j on test_hidden_index(j) invisible; // 使用invisible关键字创建一个隐藏索引
show index from test_hidden_index \G // 这时我们查看一下索引的情况
这时我们看到了Visible对应的值分别是 yes 和 no,这里就代表这是否是隐藏索引。
那么我们接下来使用explain 看一下当我们使用i和j分别作为where条件时,索引的使用情况
结论很明显,隐藏索引不可用。
我们知道在mysql5.X中引入了优化器开关选项,同理我们的是否可以使用隐藏索引进行查询也是可以配置的,接下来我们查看一下对应的配置
select @@optimizer_switch \G
这里我们只关心use_invisible_indexes的设置,这里是off,下面我们在当前回话中把这个开关打开
set session optimizer_switch = "use_invisible_indexes=on";
这时我们在进行刚才的explain就会发现隐藏索引也可以被正常的使用。
最后我们来我们尝试进行隐藏索引和正常索引的切换
alter table test_hidden_index alter index idx_j visible; // 设置成非隐藏索引
alter table test_hidden_index alter index idx_j invisible; // 设置成隐藏索引
关于隐藏索引还需要注意的是,主键不能设置为隐藏索引,这里就不进行演示了。
二、降序索引
mysql8.0开始真正支持降序索引,之前也可以创建降序索引,但是他创建的实际还是升序索引。
只有InnoDB存储引擎支持降序索引,只支持BTREE降序索引。
不再对GROUP BY操作进行隐式排序。
具体使用:
首先我们创建一个包含降序索引的表: create table test_sort_index (c1 int, c2 int, index idx_1(c1 asc, c2 desc));
这时我们发现在C2后面跟着desc,代表这一列是降序的,在8.0之前是不会这样显示的,感兴趣的同学可以自己做做实验。
接下来我们使用对应的sql进行这个索引的验证。
explain select * from test_sort_index order by c1,c2 desc \G // 跟创建索引的顺序一样
这时我们发现它可以使用索引,并且没有文件排序。如果在8.0之前,索引也是可以正常使用的,但是会多一步Using filesort,这里我们不对8.0之前进行演示了,但是我们可以使用这样一个sql模拟一下效果。
explain select * from test_sort_index order by c1 DESC ,c2 desc \G // 证明filesort的存在
那么问题来了,当我们使用索引组合完全相反的查询条件会是什么效果呢?即c1 desc c2 asc
explain select * from test_sort_index order by c1 DESC ,c2 asc \G
这时我们发现对了一个反向索引扫描的操作,也能证明B+树的叶子节点是使用的双向链表
不再对GROUP BY操作进行隐式排序这里就不演示了。
三、函数索引(有用)
mysql8.0.13开始支持在函数索引中使用函数(表达式)的值
支持降序索引,支持json数据的索引。
函数索引基于虚拟列功能实现的。
使用:
create table test_function_index (c1 varchar(10), c2 varchar(10)); // 首先我们创建一张测试表
create index idx_1 on test_function_index(c1); // 给c1创建一个普通索引
create index idx_2 on test_function_index( (UPPER(c2)) ); // 创建一个upper的函数索引
接下来我们看一下索引的情况
大家如果对innodb的索引结构了解就会清楚,针对我们上述创建的表,在聚集索引这个树可能没有的数据,可以在辅助索引的树种维护。往大了想,可以有一张上千个字段的表,然后我们需要的数据创建出来辅助索引,并且可以对原始数据进行一些数据的加工转化。
当我们使用upper函数的时候进行操作,明显c2会有效,如下图
json索引:
create table test_json_index(data json, index((CAST(data->>'$.name' as char(30))))); // cast是类型转换,也就是说把data中的name列转换成一个char(30)的列 ->>一个新的运算符。
创建了上述的索引后,当我们使用的时候也是需要使用这个表达式进行查询,
explain select * from test_json_index where CAST(data->>'$.name' as char(30)) = '' \G
对于这种函数索引,我们可以再旧版本中使用虚拟函数列实现对应的效果(当然是不考虑性能的前提下)
alter table test_virtual_function_index add column c3 varchar(10) generated always as (upper(c1));
create index idx_3 on test_virtual_function_index (c3)
explain select * from test_virtual_function_index where upper(c1) = 'a' \G