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/...

相关推荐
ONE_PUNCH_Ge10 分钟前
Go 语言泛型
开发语言·后端·golang
invicinble22 分钟前
对于mysql层对sql层面的知识体系的理解和把握
数据库·sql·mysql
良许Linux24 分钟前
DSP的选型和应用
后端·stm32·单片机·程序员·嵌入式
不光头强31 分钟前
spring boot项目欢迎页设置方式
java·spring boot·后端
怪兽毕设1 小时前
基于SpringBoot的选课调查系统
java·vue.js·spring boot·后端·node.js·选课调查系统
Nandeska1 小时前
14、MySQL基于GTID的数据同步
数据库·mysql
学IT的周星星1 小时前
Spring Boot Web 开发实战:第二天,从零搭个“会卖萌”的小项目
spring boot·后端·tomcat
郑州光合科技余经理1 小时前
可独立部署的Java同城O2O系统架构:技术落地
java·开发语言·前端·后端·小程序·系统架构·uni-app
kyle-fang1 小时前
阿里云服务器部署MySQL
服务器·mysql·阿里云
l1t1 小时前
DeepSeek辅助总结postgresql wiki提供的数独求解器
数据库·sql·postgresql