mysql如何为查询语句设计索引_mysql索引设计思路

11次阅读

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

mysql如何为查询语句设计索引_mysql索引设计思路

WHERE 条件字段必须是索引的最左前缀

MySQL 的 B+ 树索引生效依赖「最左前缀匹配」,不是 WHERE 里出现的字段就自动能走索引。比如有复合索引 INDEX idx_user_status_created (user_id, status, created_at),以下查询能用上索引:

  • WHERE user_id = 123
  • WHERE 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

执行前务必用 EXPLaiNkeypossible_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 也遵循最左前缀,且要求顺序一致。例如:

select user_id, COUNT(*) FROM orders GROUP BY user_id, status;

对应索引应为 INDEX idx_user_status (user_id, status),而非 (status, user_id) —— 后者可能触发临时表 + filesort。

如果 ORDER BYDESC,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 = 5c 不会走索引(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,最好 refconst)。真正难的是平衡多条语句的索引诉求——一条语句想要 (a,b),另一条想要 (b,c),这时候得权衡冗余索引还是拆分查询。

text=ZqhQzanResources