在MySQL8.0中,增加了对于不可见索引(invisible index)的支持,这也是一个从Oracle数据库借鉴来的新特性。

所谓不可见,指的是对于查询优化器不可见,SQL在执行时自然也不会选择,但在查看表结构的时候,索引仍然能够看到,也可以通过information_schema.statistics或者show index来查看索引是否可见的状态。

下面通过实际操作来验证一下:

-- 该命令用于查看数据库的版本
select VERSION() from dual;

mysql 定义guid mysql 定义 字段是否可见_SQL

-- 首先呢,在t1表上创建一个id的索引,并指明状态为不可见
create table t1 (

id int,

flag int,

mark int,

index id_index(id) invisible
) engine = innodb;
-- 查看t1的索引
show index from t1;

mysql 定义guid mysql 定义 字段是否可见_SQL_02


通过上面这条命令,可以看到很多信息。下面来一一解释这些字段的:

字段名

含义

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;

mysql 定义guid mysql 定义 字段是否可见_字段_03

alter table t1 add index mark_index (mark) invisible;

mysql 定义guid mysql 定义 字段是否可见_mysql_04


下面再介绍一个更加直观的去查看索引状态的SQL语句:

select index_name, is_visible
from information_schema.statistics
where table_name = 't1';

mysql 定义guid mysql 定义 字段是否可见_SQL_05


最后是修改索引的状态:

alter table t1 alter index id_index visible;

mysql 定义guid mysql 定义 字段是否可见_字段_06


接下来就要说一说为什么要设计这么一种消耗资源,却又不能够对SQL起到任何优化作用的索引呢?实际上,引入不可见索引的目的,主要是为了减小对于表上的索引进行调整时的潜在风险。

其实呢,如果你接触过工作就会知道,有一些数据表中会专门设置一个deleted字段,当执行删除的时候,去改写这个字段,用于控制这条数据不显示,而不是真正去删掉它。而不可见索引也是有这样一种异曲同工之妙。

随着表的数据量增大,达到了几百GB,几TB甚至更大的时候,如果此时对表上的索引进行调整,往往会面临很大的风险。

例如,当删除一个认为不再需要的索引时,一旦系统中还存在个别使用这个索引的SQL,那么这些SQL的执行计划有可能会变成对这个大表的全表扫描,这会对数据库服务器造成巨大冲击,很有可能直接导致服务器的不可用。而由于表的数据量大,重建索引需要的时间和消耗的系统资源也会很大,很难马上通过重建索引解决问题

有了不可见索引,当需要删除一个表上的冗余索引时,可以先将索引设置为不可见,而不是直接删除,一旦发现没有这个索引之后,对系统性能产生了负面影响,可以很方便地恢复这个索引,而不再需要重建索引。

同样,当增加一个索引之后,如果发现对系统带来了负面影响,可以首先将索引设置为不可见,待系统负载恢复正常后,再做索引的删除,避免了系统压力大的时候雪上加霜。