索引变更的风险与Invisible Index的原理
在线上MySQL环境中添加或删除索引是高风险操作。添加索引期间,MySQL需要全表扫描构建索引数据,大表的ALTER操作可能持续数小时甚至数天,期间持有MDL锁阻塞DML操作。删除索引更危险——如果查询依赖该索引,删除后可能导致全表扫描,瞬间拖垮数据库性能。
MySQL 8.0引入的Invisible Index(不可见索引)解决了这个问题。不可见索引对优化器不可见,但引擎层面仍然维护——INSERT/UPDATE/DELETE操作依然会更新不可见索引,只是SELECT查询不会使用它。这相当于一个安全的软删除机制,可以在不影响查询的情况下验证索引是否真的不需要。
Invisible Index的基本操作
-- 创建不可见索引
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 = 'mydb' AND table_name = 'orders';
安全删除索引的完整流程
Step 1:将目标索引设为不可见
ALTER TABLE orders ALTER INDEX idx_old_index INVISIBLE;
Step 2:观察期(建议至少7天)
观察期内监控慢查询日志和性能指标,确认没有查询因索引不可见而退化为全表扫描。关键监控项:
-- 检查是否有全表扫描查询
SELECT * FROM sys.schema_unused_indexes
WHERE object_schema = 'mydb';
-- 查看慢查询是否增加
SELECT * FROM mysql.slow_log
WHERE start_time > NOW() - INTERVAL 1 HOUR
ORDER BY query_time DESC LIMIT 10;
Step 3:确认安全后删除索引
ALTER TABLE orders DROP INDEX idx_old_index;
Step 4(如果发现问题):快速恢复
ALTER TABLE orders ALTER INDEX idx_old_index VISIBLE;
恢复操作是元数据级别的,瞬间完成,不需要重建索引数据。
安全添加索引的流程
添加索引同样可以用Invisible Index做预验证:
-- Step 1:创建不可见索引
ALTER TABLE orders ADD INDEX idx_new_cover (user_id, status, created_at) INVISIBLE;
-- Step 2:强制优化器使用不可见索引进行测试
SET SESSION optimizer_switch = 'use_invisible_indexes=on';
EXPLAIN SELECT user_id, status, created_at FROM orders WHERE user_id = 1001;
-- Step 3:验证执行计划正确后,设为可见
SET SESSION optimizer_switch = 'use_invisible_indexes=off';
ALTER TABLE orders ALTER INDEX idx_new_cover VISIBLE;
use_invisible_indexes=on是Session级别参数,只影响当前连接,其他会话不受影响。这样可以在生产环境中安全地测试新索引的效果。
Online DDL配合Invisible Index的最佳实践
对于大表添加索引,MySQL 8.0的Online DDL可以在不锁表的情况下完成:
ALTER TABLE large_table
ADD INDEX idx_new (column_a, column_b) INVISIBLE,
ALGORITHM=INPLACE,
LOCK=NONE;
ALGORITHM=INPLACE表示在原表上操作,不拷贝全表数据;LOCK=NONE允许并发DML。但需要注意:
1. Online DDL期间仍然需要短暂的MDL锁(开始和结束阶段),如果此时有长事务持有MDL锁,DDL会等待。
2. Inplace方式创建索引需要额外的临时空间,大约是索引大小的1-2倍。
3. 对于超大表(数十亿行),考虑使用pt-online-schema-change或gh-ost工具,它们通过创建影子表加增量同步的方式实现零锁表变更。
降级索引与索引合并策略
当索引策略需要调整但不希望完全删除旧索引时,降级索引是一个折中方案——将旧索引设为不可见,创建新索引替代。如果新索引效果不理想,旧索引可以秒级恢复:
-- 降级旧索引
ALTER TABLE orders ALTER INDEX idx_old_composite INVISIBLE;
-- 创建新索引
ALTER TABLE orders ADD INDEX idx_new_composite (col_a, col_b, col_c) VISIBLE;
-- 如果新索引有问题,快速回滚
ALTER TABLE orders ALTER INDEX idx_old_composite VISIBLE;
ALTER TABLE orders DROP INDEX idx_new_composite;
Invisible Index是MySQL 8.0给DBA最重要的安全工具之一。结合use_invisible_indexes的Session级测试和Online DDL,索引变更的风险可以降到极低。核心原则:先不可见再删除,先不可见测试再可见上线。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql80invisibleindex-yu-jiang-ji-suo-yin-ling-feng-xian/