mysql索引优化常见错误有哪些_mysql避坑指南

来源:这里教程网 时间:2026-02-28 20:48:28 作者:

索引列顺序写反了,
WHERE a = ? AND b = ?
却建了
(b, a)

复合索引的列顺序不是随便排的。MySQL 用最左前缀匹配,

(b, a)
索引对
WHERE a = ?
完全无效,连
WHERE b = ? AND a = ?
也只用上第一层。实际执行时可能走全表扫描。

实操建议:

按查询条件中等值过滤列优先、范围查询列靠后、排序/分组列最后的顺序建索引
WHERE tenant_id = ? AND status = ? ORDER BY created_at DESC
→ 推荐索引:
(tenant_id, status, created_at)
EXPLAIN
key_len
Extra
字段:如果
key_len
明显偏小,或出现
Using filesort
,大概率顺序不合理

SELECT *
搭配覆盖索引失效

覆盖索引要求查询字段全部被索引包含,但

SELECT *
会拉出所有列,哪怕你建了
(a, b, c)
索引,只要表里还有
d
字段,就无法触发覆盖,必然回表。

实操建议:

明确只查需要的字段,比如改
SELECT *
SELECT a, b, c
若高频查询固定几列,可建联合索引并确保字段全覆盖,例如:
CREATE INDEX idx_cover ON t (a, b, c);
注意
TEXT
/
BLOB
类型不能建在索引中,即使声明了也会被忽略,导致你以为“覆盖”了其实没覆盖

在索引列上做函数或计算,
WHERE YEAR(created_at) = 2024

只要对索引列用了函数、表达式、类型转换,索引就直接失效。MySQL 无法用 B+ 树快速定位

YEAR(created_at)
的结果,只能全扫。

实操建议:

把函数移到右边:
WHERE created_at >= '2024-01-01' AND created_at 
避免隐式类型转换:
WHERE user_id = '123'
user_id
INT
)会触发转换,改成
WHERE user_id = 123
字符串比较注意 collation,
utf8mb4_0900_as_cs
utf8mb4_general_ci
混用可能导致索引跳过

过度索引:给每个
WHERE
字段都单独建索引

单列索引多而杂,不仅不加速,反而拖慢写入(每次 INSERT/UPDATE 都要维护多个 B+ 树),还可能让优化器选错执行计划。

实操建议:

优先合并:已有
(a, b)
索引时,
WHERE a = ?
WHERE a = ? AND b = ?
都能用上,不必再建
(a)
删掉长期没用的索引:查
sys.schema_unused_indexes
视图(MySQL 8.0+),或用
performance_schema.table_io_waits_summary_by_index_usage
注意前缀索引陷阱:
INDEX (email(16))
可能导致
WHERE email = 'x@y.z'
匹配失败,除非所有邮箱前 16 字符都唯一
索引优化真正的难点不在“建不建”,而在“查什么、怎么查、数据长什么样”。线上慢查必须结合
EXPLAIN
、真实数据分布、QPS 和写入压力一起看,脱离场景谈索引,90% 是纸上谈兵。

相关推荐