MySQL 8.0不可见索引的原理与使用场景
MySQL 8.0引入的不可见索引(Invisible Index)允许将索引标记为对优化器不可见,但索引数据结构仍然存在并可维护。这个功能解决了一个长期痛点:删除索引后的回退风险。生产环境中删除索引后若查询性能骤降,重建索引可能需要数小时,期间业务受严重影响。不可见索引提供了一种安全的”软删除”机制——先将索引设为不可见观察性能变化,确认无影响后再真正删除。
不可见索引的核心机制:InnoDB存储引擎仍正常维护索引(INSERT/UPDATE/DELETE时同步更新索引结构),但优化器在生成执行计划时不考虑该索引。这意味着索引的维护成本不变,但查询优化器不会选择它作为访问路径。
不可见索引操作语法与验证方法
-- 创建不可见索引
ALTER TABLE orders
ADD INDEX idx_status_created (status, created_at) INVISIBLE;
-- 将已有索引设为不可见
ALTER TABLE orders
ALTER INDEX idx_status_created INVISIBLE;
-- 恢复索引可见性
ALTER TABLE orders
ALTER INDEX idx_status_created VISIBLE;
-- 查看索引可见性状态
SELECT index_name, is_visible
FROM information_schema.statistics
WHERE table_schema = 'shop_db'
AND table_name = 'orders';
验证不可见索引是否被优化器忽略,使用EXPLAIN查看执行计划:
-- 索引可见时,优化器选择idx_status_created
EXPLAIN SELECT * FROM orders WHERE status = 'PAID' ORDER BY created_at DESC;
-- type: ref, key: idx_status_created
-- 将索引设为不可见后
ALTER TABLE orders ALTER INDEX idx_status_created INVISIBLE;
EXPLAIN SELECT * FROM orders WHERE status = 'PAID' ORDER BY created_at DESC;
-- type: ALL, key: NULL (全表扫描)
若不可见后查询性能急剧下降,说明该索引是关键索引,应立即恢复可见。若无性能影响,可安全删除。
降序索引的工作机制与排序优化
MySQL 8.0之前创建的降序索引(DESC)实际上被忽略,索引始终按升序存储。MySQL 8.0真正支持了降序索引——索引键可按降序存储,对包含ORDER BY … DESC的查询可避免额外的filesort操作。
-- 创建含降序键的复合索引
ALTER TABLE orders
ADD INDEX idx_user_created (user_id, created_at DESC);
-- 对应查询可直接利用索引有序性,避免filesort
SELECT * FROM orders
WHERE user_id = 1001
ORDER BY created_at DESC
LIMIT 20;
EXPLAIN结果中Extra列若显示Backward index scan,说明优化器正在反向扫描升序索引来满足DESC排序。若索引已定义为DESC,则显示Using index,无需反向扫描。两种方式功能等价,但降序索引在范围扫描场景下性能更优——Backward index scan无法利用索引的顺序性做范围过滤。
性能对比测试:降序索引vs反向扫描
以下测试基于1000万条orders表数据,对比升序索引反向扫描与降序索引正向扫描的性能差异:
-- 测试1:升序索引 + Backward index scan
ALTER TABLE orders ADD INDEX idx_created_asc (user_id, created_at ASC);
SELECT * FROM orders
WHERE user_id = 1001 AND created_at > '2026-01-01'
ORDER BY created_at DESC LIMIT 20;
-- 测试2:降序索引 + 正向扫描
ALTER TABLE orders ADD INDEX idx_created_desc (user_id, created_at DESC);
SELECT * FROM orders
WHERE user_id = 1001 AND created_at > '2026-01-01'
ORDER BY created_at DESC LIMIT 20;
测试结果对比:
场景 | 执行时间(ms) | Rows Examined | Extra
-----------------------|-------------|---------------|-------------------
升序索引+反向扫描 | 45 | 1,523 | Backward index scan
降序索引+正向扫描 | 12 | 1,523 | Using index
升序索引+filesort | 380 | 52,410 | Using filesort
降序索引在范围查询+DESC排序场景下性能提升约3.7倍。关键差异在于:降序索引的B+Tree叶子节点按键值降序链接,正向遍历即满足DESC排序,无需反向扫描的开销。当查询涉及范围过滤时,降序索引可精确定位起始位置后顺序读取,Backward index scan则需要先定位末端再反向遍历,定位成本更高。
不可见索引与降序索引的组合应用
生产环境中替换索引的最佳实践:先创建降序索引(不可见),与旧索引并行存在,验证后切换可见性,最后删除旧索引:
-- Step 1: 创建降序索引(不可见),不影响现有查询
ALTER TABLE orders
ADD INDEX idx_user_created_v2 (user_id, created_at DESC) INVISIBLE;
-- Step 2: 填充索引数据(InnoDB自动完成)
-- 等待索引构建完成,大表可能需要较长时间
-- Step 3: 交换可见性
ALTER TABLE orders ALTER INDEX idx_user_created INVISIBLE;
ALTER TABLE orders ALTER INDEX idx_user_created_v2 VISIBLE;
-- Step 4: 观察查询性能
EXPLAIN SELECT * FROM orders
WHERE user_id = 1001
ORDER BY created_at DESC LIMIT 20;
-- Step 5: 确认无误后删除旧索引
ALTER TABLE orders DROP INDEX idx_user_created;
这种索引替换策略确保了零停机时间:新索引在不可见状态下构建完成,可见性切换是元数据操作,几乎瞬时完成。若新索引存在问题,只需交换可见性即可回退,比删除重建快数个数量级。
optimizer_switch控制与调试技巧
MySQL 8.0提供optimizer_switch系统变量控制优化器是否使用不可见索引。会话级别开启后,可用于调试验证:
-- 会话级别启用不可见索引(仅用于调试)
SET SESSION optimizer_switch = 'use_invisible_indexes=on';
-- 此时EXPLAIN可看到不可见索引被考虑
EXPLAIN SELECT * FROM orders WHERE status = 'PAID';
-- 调试完毕关闭
SET SESSION optimizer_switch = 'use_invisible_indexes=off';
use_invisible_indexes=on在优化器层面等同于将所有不可见索引临时设为可见,不会修改索引元数据。这个开关适合在诊断性能问题时临时使用——如果开启后查询变快,说明某个不可见索引不应被删除。
结合sys.schema_unused_indexes视图可识别长期未使用的索引,将其设为不可见观察一段时间后再决定删除,比直接删除安全得多。这种”先观察后操作”的工作流是MySQL索引管理的最佳实践。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql80-bu-ke-jian-suo-yin-yu-jiang-xu-suo-yin-shi-zhan-pei/