MySQL索引生效需满足最左前缀原则,等值查询应前置、范围查询置后;避免对索引列使用函数;ORDER BY/GROUP BY需匹配索引顺序;索引并非越多越好,应结合选择性和慢查询优化。

WHERE 条件字段必须是索引的最左前缀
MySQL 的 B+ 树索引生效依赖「最左前缀匹配」,不是 WHERE 里出现的字段就自动能走索引。比如有复合索引 INDEX idx_user_status_created (user_id, status, created_at),以下查询能用上索引:
WHERE user_id = 123WHERE user_id = 123 AND status = 'active'WHERE user_id = 123 AND status = 'active' AND created_at > '2024-01-01'
但这些不行:
-
WHERE status = 'active'(跳过user_id,无法命中) -
WHERE created_at > '2024-01-01'(完全不满足最左前缀) -
WHERE status = 'active' AND created_at > '2024-01-01'(缺少user_id)
执行前务必用 EXPLAIN 看 key 和 possible_keys 是否匹配预期,别凭感觉。
避免在索引列上做计算或函数操作
对索引字段使用函数、表达式或类型转换,会直接导致索引失效。常见踩坑点:
-
WHERE YEAR(created_at) = 2024→ 改成WHERE created_at >= '2024-01-01' AND created_at -
WHERE UPPER(name) = 'JOHN'→ 改成建函数索引(MySQL 8.0+):CREATE INDEX idx_name_upper ON users ((UPPER(name))),或统一存大写 -
WHERE age + 1 > 30→ 改成WHERE age > 29
注意:MySQL 8.0 支持函数索引,但低版本只能靠冗余字段或改写条件。
ORDER BY 和 GROUP BY 要尽量复用索引顺序
如果查询含 ORDER BY a, b,而索引是 (a, b, c),就能避免 filesort;但如果索引是 (b, a) 或 (a, c, b),就无法覆盖排序需求。
同样,GROUP BY 也遵循最左前缀,且要求顺序一致。例如:
系统功能强大、操作便捷并具有高度延续开发的内容与知识管理系统,并可集合系统强大的新闻、产品、下载、人才、留言、搜索引擎优化、等功能模块,为企业部门提供一个简单、易用、开放、可扩展的企业信息门户平台或电子商务运行平台。开发人员为脆弱页面专门设计了防刷新系统,自动阻止恶意访问和攻击;安全检查应用于每一处代码中,每个提交到系统查询语句中的变量都经过过滤,可自动屏蔽恶意攻击代码,从而全面防止SQL注入攻击
SELECT user_id, COUNT(*) FROM orders GROUP BY user_id, status;
对应索引应为 INDEX idx_user_status (user_id, status),而非 (status, user_id) —— 后者可能触发临时表 + filesort。
如果 ORDER BY 是 DESC,MySQL 8.0+ 支持在索引中显式声明方向:INDEX idx_created_desc (created_at DESC);5.7 及以前,混合 ASC/DESC 会退化为 filesort。
区分等值查询和范围查询的位置
在复合索引中,**等值条件(=、IN)应放在范围条件(>、
例如索引 (a, b, c):
-
WHERE a = 1 AND b > 10 AND c = 5→c不会走索引(b是范围,中断了最左前缀) -
WHERE a = 1 AND c = 5 AND b > 10→ 同样无效,顺序不影响解析逻辑,MySQL 按索引定义顺序匹配 - 正确设计应把高频等值字段前置,范围字段放最后,如
(a, c, b)适配a = ? AND c = ? AND b > ?
实际建索引前,先用 SELECT DISTINCT 或慢日志分析字段的过滤选择性,高选择性字段(如 user_id)比低选择性字段(如 status,只有 active/inactive)更适合放前面。
索引不是越多越好,每多一个索引都增加写开销和内存占用。重点盯住慢查询日志里的 Rows_examined 和执行计划中的 type(至少到 range,最好 ref 或 const)。真正难的是平衡多条语句的索引诉求——一条语句想要 (a,b),另一条想要 (b,c),这时候得权衡冗余索引还是拆分查询。









