在MySQL8.0中,增加了对于不可见索引(invisible index)的支持,这也是一个从Oracle数据库借鉴来的新特性。
所谓不可见,指的是对于查询优化器不可见,SQL在执行时自然也不会选择,但在查看表结构的时候,索引仍然能够看到,也可以通过information_schema.statistics或者show index来查看索引是否可见的状态。
下面通过实际操作来验证一下:
-- 该命令用于查看数据库的版本
select VERSION() from dual;
-- 首先呢,在t1表上创建一个id的索引,并指明状态为不可见
create table t1 (
id int,
flag int,
mark int,
index id_index(id) invisible
) engine = innodb;
-- 查看t1的索引
show index from t1;
通过上面这条命令,可以看到很多信息。下面来一一解释这些字段的:
字段名 | 含义 |
Table | 表名 |
Non_unique | 如果索引不能包括重复词,则为0。如果可以,则为1 |
Key_name | 索引的名称 |
Seq_in_index | 索引中的列序列号,从1开始 |
Column_name | 索引作用在哪个字段上 |
Collation | 列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类) |
Cardinality | 索引中唯一值的数目的估计值。 |
Sub_part | 如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL |
Packed | 指示关键字如何被压缩。如果没有被压缩,则为NULL |
Null | 如果列含有NULL,则含有YES。如果没有,则该列含有NO |
Index_type | 用的索引类型(BTREE, FULLTEXT, HASH, RTREE) |
Comment | 多种评注 |
Index_comment | 为索引创建时提供了一个注释属性的索引的任何评论 |
Visible | 索引是否可见 |
Expression | 索引表达式 |
除了在创建表的时候创建索引,也可以通过下面这些命令去创建索引;
create index flag_index on t1(flag) invisible;
alter table t1 add index mark_index (mark) invisible;
下面再介绍一个更加直观的去查看索引状态的SQL语句:
select index_name, is_visible
from information_schema.statistics
where table_name = 't1';
最后是修改索引的状态:
alter table t1 alter index id_index visible;
接下来就要说一说为什么要设计这么一种消耗资源,却又不能够对SQL起到任何优化作用的索引呢?实际上,引入不可见索引的目的,主要是为了减小对于表上的索引进行调整时的潜在风险。
其实呢,如果你接触过工作就会知道,有一些数据表中会专门设置一个deleted字段,当执行删除的时候,去改写这个字段,用于控制这条数据不显示,而不是真正去删掉它。而不可见索引也是有这样一种异曲同工之妙。
随着表的数据量增大,达到了几百GB,几TB甚至更大的时候,如果此时对表上的索引进行调整,往往会面临很大的风险。
例如,当删除一个认为不再需要的索引时,一旦系统中还存在个别使用这个索引的SQL,那么这些SQL的执行计划有可能会变成对这个大表的全表扫描,这会对数据库服务器造成巨大冲击,很有可能直接导致服务器的不可用。而由于表的数据量大,重建索引需要的时间和消耗的系统资源也会很大,很难马上通过重建索引解决问题。
有了不可见索引,当需要删除一个表上的冗余索引时,可以先将索引设置为不可见,而不是直接删除,一旦发现没有这个索引之后,对系统性能产生了负面影响,可以很方便地恢复这个索引,而不再需要重建索引。
同样,当增加一个索引之后,如果发现对系统带来了负面影响,可以首先将索引设置为不可见,待系统负载恢复正常后,再做索引的删除,避免了系统压力大的时候雪上加霜。