索引越多,查询越快?别信这个直觉
不是。索引本身不加速所有查询,反而在写入时强制增加开销,且会显著拖慢
INSERT、
UPDATE、
DELETE操作。MySQL 每次修改数据,都要同步更新对应索引的 B+ 树结构——索引越多,维护成本越高。
更关键的是:无效索引会持续占用内存和磁盘空间,影响 Buffer Pool 利用率,甚至导致执行计划误判(比如优化器因索引过多而选错
key)。
哪些索引大概率是“假有用”?
以下几类索引常被误建,实际几乎不被优化器选用:
status这类低基数字段(如只有
'active'/
'inactive')单独建索引,MySQL 通常直接走全表扫描,因为回表代价可能比扫一遍还高 重复前缀的联合索引,例如已有
(user_id, created_at),又额外建了
(user_id)—— 后者完全被前者覆盖 只在
ORDER BY中出现、却不在
WHERE条件里的字段索引(如
ORDER BY updated_at但无
WHERE updated_at > ?),除非配合
LIMIT且数据量极小,否则基本无效 频繁
LIKE '%xxx'模糊查询的字段建普通 B-Tree 索引,根本用不上
怎么判断一个索引是否真被用了?
别靠猜,用
EXPLAIN和
information_schema.STATISTICS交叉验证: 执行
EXPLAIN SELECT ...,重点看
key列是否显示该索引名,以及
rows是否明显下降 查
sys.schema_unused_indexes(MySQL 8.0+)或手动统计
performance_schema.table_io_waits_summary_by_index_usage,确认该索引自启动后
COUNT_STAR = 0注意:即使
EXPLAIN显示用了某个索引,也要结合
type值判断——如果是
index或
ALL,说明只是扫描索引树或全表,并非高效查找
SELECT * FROM sys.schema_unused_indexes WHERE object_schema = 'your_db' AND object_name = 'your_table';
建索引前必须问的三个问题
每加一个索引,都该明确回答:
这个查询是否高频?低频查询不值得用写入代价换读取收益 这个索引能否支撑多个查询?优先建能复用的联合索引(按WHERE等值 →
IN→
ORDER BY字段顺序排列) 有没有更轻量的替代?比如把
JSON字段拆成普通列再索引,或用生成列(
GENERATED COLUMN)+ 索引替代复杂表达式查询
真正难的不是“怎么建索引”,而是“为什么这里不该建”。线上表一旦有千万级数据,删一个无用索引都可能锁表几分钟——设计阶段多花十分钟想清楚,后期省的不止是磁盘和 CPU。
