登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL 不可见索引怎么验收:optimizer_switch、影子验证与恢复边界

来源:17golang原创

时间:2026-08-24 12:20:54 308浏览 收藏

线上订单列表准备下掉一条疑似重复索引时,直接执行 DROP INDEX 往往太快了。MySQL 的不可见索引可以先让优化器忽略它,但索引仍然存在,应用还能用同一套 SQL 做回归核对。真正稳妥的做法是:先保存执行计划,再切换可见性,最后用单会话验证和监控结果决定是否恢复或删除。

不可见索引适合做低风险预演,不等于删除前的自动回滚。切换前后都要核对执行计划、响应时间和线上错误。

实践要点:
  • 先确认索引名和受影响 SQL。
  • ALTER TABLE ... ALTER INDEX ... INVISIBLE 做全局预演。
  • 需要对照时,在测试会话打开 use_invisible_indexes
  • 出现计划退化就立即恢复 VISIBLE。

先看清这条索引到底保护了什么

假设订单表上有联合索引 idx_orders_user_status_created,查询按用户、状态和创建时间筛选。切换前先记录定义与计划,不要只看索引名字:

SHOW INDEX FROM orders;
EXPLAIN FORMAT=TREE
SELECT id, status, created_at
FROM orders
WHERE user_id = 42 AND status = 'paid'
ORDER BY created_at DESC
LIMIT 50;

重点记下访问类型、使用的索引、估算行数和排序是否落到磁盘。若业务还依赖这条索引覆盖另一组查询,只凭一条 SQL 的结果就下线,会把风险藏到别的入口。

MySQL 订单查询从可见索引切换为不可见索引后的执行计划证据

把索引设为不可见,观察全局计划变化

MySQL 8.0 及以上可以直接修改索引可见性。索引不会立刻消失,写入维护也仍然存在,所以这一步主要是验证优化器不再主动选择它。

ALTER TABLE orders
  ALTER INDEX idx_orders_user_status_created INVISIBLE;

EXPLAIN FORMAT=TREE
SELECT id, status, created_at
FROM orders
WHERE user_id = 42 AND status = 'paid'
ORDER BY created_at DESC
LIMIT 50;

重新执行计划后,不要只比较“有没有走索引”。如果换成了另一个索引,要继续看估算行数、回表次数、排序和实际耗时。生产环境建议先在低峰期做,并给这次变更标记清晰的开始时间,便于和慢日志对齐。

用单会话做影子对照,不要用全局开关

想在索引已经不可见时继续测试它,可以只对当前连接开启优化器选项。这样不会把其他应用连接一起改掉:

SET SESSION optimizer_switch = 'use_invisible_indexes=on';

EXPLAIN FORMAT=TREE
SELECT id, status, created_at
FROM orders
WHERE user_id = 42 AND status = 'paid'
ORDER BY created_at DESC
LIMIT 50;

SET SESSION optimizer_switch = 'use_invisible_indexes=off';

这个会话级对照适合压测、回放和人工复核。测试结束要显式恢复选项,连接池复用连接时尤其要注意:一个遗留的会话变量可能让后续请求看到和普通连接不同的计划。

MySQL 单会话开启不可见索引对照并恢复设置的检查流程

计划变差时,恢复可见性比继续调 SQL 更重要

如果慢日志显示排序放大、扫描行数明显上升,先恢复索引,不要急着通过改写业务 SQL 掩盖问题:

ALTER TABLE orders
  ALTER INDEX idx_orders_user_status_created VISIBLE;

SHOW INDEX FROM orders;
SHOW WARNINGS;

恢复后重新跑一条代表性查询,并检查连接池中的新旧连接。不可见状态改变的是优化器候选集合,不会替你判断索引是否重复,也不会代替变更审批、回滚记录和容量评估。

几个容易误判的边界

不可见索引是不是已经不占空间?

不是。它仍然是维护中的索引,写入时仍有成本;只有确认不再需要后,才进入删除与空间回收流程。

为什么计划没变,耗时却变了?

执行计划只是估算路径,缓存、数据分布、并发和磁盘状态都会影响实际耗时。至少结合多次执行、慢日志和实际行数观察,别用一次请求作结论。

能不能直接改全局 optimizer_switch?

不建议把影子验证开关扩散到全局。优先使用会话级设置,并在验证脚本结束时恢复;变更记录里写明索引可见性和连接范围。

常见问题:不可见索引验收怎么判断

验证多久可以决定删除?

至少覆盖一轮完整业务高峰,并让关键查询都有前后基线。若业务流量有明显周期开关,应覆盖最容易触发慢查询的时段。

恢复 VISIBLE 会不会重建索引?

可见性切换本身不是重新创建索引,但恢复后仍应重新核对计划和实际耗时,确认优化器已重新把它纳入候选集合。

收尾检查:恢复、保留还是删除

验证通过也不要立即删除。先确认所有关键查询都有基线,观察一个完整业务窗口,再决定保留不可见状态或安排删除。最终检查至少包括:索引定义、关键 SQL 计划、实际耗时、慢日志、错误率,以及回滚命令是否已演练。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>