索引隐藏

Exisi 2023-04-12 17:24:30
Categories: Tags:
  • MySQL 8.0 后支持隐藏索引(invisible index),主要用于测试索引删除后产生的查询性能影响。索引隐藏适用于除主键索引(显示或者隐式设置)之外的索引,而主键索引不能通过任何方式隐藏。

 

  • MySQL 数据库默认创建的索引都是可见的,要显式控制一个索引的可见性,可以在 CREATE TABLECREATE INDEX ALTER TABLE 的索引定义命令中使用 VISIBLE INVISIBLE 关键字。

示例

CREATE TABLE user (

id INT PRIMARY KEY,

name VARCHAR(25),

age INT,

weight INT,

INDEX name_idx (name) INVISIBLE

) ENGINE = InnoDB;

 

ALTER TABLE user ADD INDEX age_idx (age) INVISIBLE;

 

CREATE INDEX weight_idx ON user (weight) INVISIBLE;

 

  • 系统变量 optimizer_switch use_invisible_indexes 值控制了优化器执行计划构建时是否使用隐藏后的索引。当索引隐藏不被优化器所使用时,用于索引的软删除。

语法

SET optimizer_switch='use_invisible_indexes=on';

 

SET optimizer_switch='use_invisible_indexes=off';

 

参数

描述

off

关闭状态(默认值),优化器默认会忽略隐藏索引,即和加入该参数之前的效果一样。

on

 打开状态,隐藏索引仍然保持不可见,但优化器会把隐藏索引加入到执行计划的构建中。

 

  • 利用索引隐藏快速测试删除索引后对 SQL 查询性能的影响,而无需进行索引删除、重建操作。如果需要该索引,再设置可见就好了,这在大表测试中无疑非常有用,因为对于大表索引的删除和重新添加很耗性能,甚至影响表的正常工作。

 

  • 索引隐藏后,如果想要在某条单个 SQL 查询语句上对优化器启用,可以使用 SET_VAR 优化器提示来临时更新 optimizer_switch 的值,如下所示:

示例

SELECT

SET_VAR(optimizer_switch = 'use_invisible_indexes=on')

age,

name

FROM user

  • 虽然索引隐藏不会被优化器使用,但仍然需要进行维护

 

  • 索引的可见性不会影响索引的自身维护,例如,不管索引是可见还是不可见,每次表数据行的更改索引都会更新,并且唯一索引也可防止插入重复数据。

 

  • 没有显式主键的表如果在 NOT NULL 列上有任何一个唯一索引,则仍可能成为有效的隐式主键。在这种情况下,第一个这样的索引会对表数据行施加与显式主键相同的约束,并且该索引不能设置为不可见。

 

 

 

查看隐藏的索引

  • 使用 SHOW CREATE TABLE 语句查看索引定义,索引隐藏后会附加注释: /*!80000 INVISIBLE */

示例

SHOW CREATE TABLE user

 

运行结果如下:

*************************** 1. row ***************************

            Table: user

Create Table: CREATE TABLE `user` (

  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,

  `name` varchar(20) ,

  KEY `idx_name` (`name`) /*!80000 INVISIBLE */,

) ENGINE=InnoDB DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

 

  • 使用 SHOW INDEX 查看索引的可见性,VISIBLE字段为YES,即可见,NO即不可见

示例

SHOW INDEX FROM user

 

运行结果如下:

 

  •  information_schema.STATISTICS.IS_VISIBLE 字段可以查看确认是否可见

示例

SELECT

TABLE_SCHEMA,

TABLE_NAME,

INDEX_NAME,

IS_VISIBLE

FROM STATISTICS

WHERE table_schema='slower'

AND table_name='user';

 

运行结果如下:

+---------------------+------------------+------------------+----------------+

| TABLE_SCHEMA | TABLE_NAME | INDEX_NAME | IS_VISIBLE |

+---------------------+------------------+------------------+----------------+

| slower                  | user                  | idx_name          | NO                |

| slower                  | user                  | PRIMARY          | YES              |

+---------------------+------------------+------------------+----------------+

 

 

来自 <https://zhuanlan.zhihu.com/p/346955808>