MySQL索引优化-索引可见性

MySQL 支持隐式索引,即优化器不使用的索引。适用于主键(显式或隐式)以外的索引。

索引默认是可见的。要显式控制新索引的可见性,可以在 CREATE TABLECREATE INDEXALTER TABLE 的索引定义中使用 VISIBLEINVISIBLE 关键字,举个栗子:

sql 复制代码
-- 建表
CREATE TABLE t1 ( 
    i INT, 
    j INT, 
    k INT, 
    INDEX i_idx (i) INVISIBLE 
) ENGINE = InnoDB; 

-- 建索引
CREATE INDEX j_idx ON t1 (j) INVISIBLE; 
ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;

如果要修改现有索引的可见性,也同样使用 ALTER TABLE ... VISIBLEINVISIBLE 关键字。ALTER INDEX 也是同样,举个栗子:

sql 复制代码
ALTER TABLE t1 ALTER INDEX i_idx INVISIBLE; 
ALTER TABLE t1 ALTER INDEX i_idx VISIBLE;

关于索引可见或不可见的信息,可以从 information_schemaSTATISTICS 表或 SHOW INDEX 输出中查询,比如:

sql 复制代码
select * from information_schema.STATISTICS where TABLE_NAME = 't1' and TABLE_SCHEMA = 'test'

输出:

TABLE_SCHEMA TABLE_NAME ... INDEX_NAME COLUMN_NAME IS_VISIBLE
i_idx test ... i_idx i NO
k_idx test ... k_idx k YES

执行SQL:

sql 复制代码
show index from t1

输出:

Table Key_name ... Visible
t1 i_idx ... NO
t1 k_idx ... YES

核心机制和作用

1. 非破坏性测试

通过将索引标记为不可见(ALTER INDEX ... INVISIBLE),用来 测试删除索引对查询性能的影响 ,数据库优化器将自动忽略该索引,使开发人员能够精准评估索引删除后的查询执行计划变化。此操作仅修改数据字典中的元数据标记,无需重构物理存储结构,能有效规避传统DROP INDEX操作带来的风险:

  • 事务回滚导致的锁表风险
  • 统计信息丢失引发的执行计划震荡
  • 物理删除索引后重建的I/O资源消耗

2. 快速恢复特性

当确认索引必要性后,执行ALTER INDEX ... VISIBLE即可在毫秒级恢复索引功能,特别适合大型数据表运维场景。

3. 影响和使用

如果标记索引为不可见之后,有几种方法可以观察到对表查询的影响:

  • 对于包含索引提示 的查询,如果索引提示使用了不可见索引,会报错。
  • 查询有不同的 EXPLAIN 执行计划。
  • 慢查询日志中可能会增多。

optimizer_switch 系统变量的 use_invisible_indexes 标志控制优化器是否使用不可见索引来构建查询执行计划,默认 use_invisible_indexes=off,优化器将忽略不可见索引,如果设置为on,则不可见索引仍然不可见,但优化器在构建执行计划时仍会将其考虑在内。

使用 SET_VAR 优化器提示临时更新 optimizer_switch 的值,可以在单次查询期间启用不可见索引,举个栗子:

先随机生成1000条数据到t1表中:

sql 复制代码
INSERT INTO t1 (i, j, k)
SELECT

        RAND() * 10,
        RAND() * 10,
        RAND() * 10
     AS random_text
FROM (
    WITH RECURSIVE numbers (n) AS (
        SELECT 1                  -- 初始值
        UNION ALL
        SELECT n + 1 FROM numbers -- 递归增加
        WHERE n < 1000            -- 停止条件(生成 1000 行)
    )
    SELECT n FROM numbers
) AS seq;

使用优化器提示执行Explain:

sql 复制代码
explain select /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ * from t1 where i = 1;

输出结果:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ref i_idx i_idx 5 const 105 100

普通查询执行Explain:

sql 复制代码
explain select  * from t1 where i = 1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL 1000 0.1 Using where

索引可见性不会影响索引维护。例如,无论索引是可见还是不可见,索引都会根据表行的变化继续更新,唯一索引会防止在列中插入重复内容。

如果一个没有显式定义主键索引的表在 NOT NULL 列上有任何 UNIQUE 索引,那它仍然可能有一个有效的隐式主键。在这种情况下,第一个此类索引对表行施加的约束与显式主键相同,因此不能将该索引设置为不可见。举个栗子:

sql 复制代码
CREATE TABLE t2 (
    i INT NOT NULL, 
    j INT NOT NULL, 
    UNIQUE j_idx (j) 
) ENGINE = InnoDB;

这个表没有定义主键,但在列 j 上的 NOT NULL 索引对行施加了与主键相同的约束,这种情况没办法设置INVISABLE

sql 复制代码
mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE;

-- ERROR 3522 (HY000): A primary key index cannot be invisible.

如果在表中添加了一个显式主键:

sql 复制代码
ALTER TABLE t2 ADD PRIMARY KEY (i);

显式主键不能被隐藏。此外,j 上的唯一索引不再作为隐式主键,所以可以设置INVISIBLE

sql 复制代码
mysql> ALTER TABLE t2 ALTER INDEX j_idx INVISIBLE; 

-- Query OK, 0 rows affected (0.03 sec)

参考文档:dev.mysql.com/doc/refman/...

相关推荐
汪子熙10 分钟前
理解 SSH Agent 的工作原理与应用场景
后端
苏琢玉20 分钟前
如何优雅地处理多种电商优惠规则?我用 PHP 封装了一个 Promotion Engine
后端·php·composer
豌豆花下猫22 分钟前
Python 潮流周刊#113:用虚拟线程取代 async/await
后端·python·ai
武子康23 分钟前
大数据-58 Kafka 消息发送全流程详解:序列化、分区策略与自定义实现
大数据·后端·kafka
福大大架构师每日一题24 分钟前
2025-08-02:最多 K 个元素的子数组的最值之和。用go语言,给定一个整数数组 nums 和一个正整数 k,请找出所有长度最多为 k 的连续子数组,计算
后端
Debug笔记24 分钟前
你真的理解 Java 中的线程池吗?一次“查不出原因的接口变慢”的真实排查经历
后端
Cache技术分享25 分钟前
149. Java Lambda 表达式 - Lambda 表达式的序列化
前端·后端
Debug笔记29 分钟前
MySQL 慢查询优化实战:看懂执行计划,性能提升 10 倍不是梦。
mysql
_風箏30 分钟前
Shell【脚本 01】实现定时备份文件、压缩、删除超时文件操作(showDoc文件备份脚本举例)
后端
橘黄的猫37 分钟前
MacBook Pro 安装 Java 开发环境指南
后端