mysql联合索引需按最左前缀原则设计,等值字段前置、范围字段后置,order by/group by字段须紧接where等值条件后;函数或表达式会导致索引失效,应优化写法或用生成列。

WHERE 条件中字段的出现顺序决定索引列顺序
MySQL 的 B+ 树索引是按定义顺序逐列比较的,WHERE a = 1 AND b = 2 AND c > 3 这类查询,只有把 a 放在索引最左,才能用上整个索引。如果索引是 (b, a, c),那 a 就无法走最左前缀,只能用到 b 那一列(前提是 b 有等值条件)。
实操建议:
- 把等值查询(
=、IN)字段放前面,范围查询(>、BETWEEN、LIKE 'abc%')放后面 - 如果多个字段都是等值查询,把区分度高(基数大)的字段放更左,比如
user_id比status更适合作为第一列 - 避免把经常单独查的低频字段放在最左,否则其他组合查询可能用不上这个索引
ORDER BY 和 GROUP BY 字段必须紧接在 WHERE 等值条件之后
MySQL 只有在索引能“覆盖”排序或分组时,才避免额外的 filesort 或 temporary table。例如 SELECT * FROM t WHERE a = 1 ORDER BY b, c,索引 (a, b, c) 可以复用;但若写成 (a, c, b),b 不在连续位置,就无法利用索引排序。
常见错误现象:
-
EXPLAIN结果中Extra列出现Using filesort,说明排序没走索引 -
GROUP BY后字段顺序和索引不一致,哪怕所有字段都在索引里,也可能触发临时表 - 混合 ASC/DESC(如
ORDER BY b ASC, c DESC)在 MySQL 8.0 之前无法用索引排序,8.0+ 要求索引定义也显式声明方向
联合索引不是“字段集合”,重复建单列索引往往没用
有联合索引 (a, b, c),它天然包含 (a) 和 (a, b) 的能力,但不包含 (b) 或 (c) 单独查询的能力。此时再单独建 INDEX(b),不是补充,而是冗余——除非你真有高频的 WHERE b = ? 查询且无法改写 SQL。
Yes!Sun基于PHP+MYSQL技术,体积小巧、应用灵活、功能强大,是一款为企业网站量身打造的WEB系统。其创新的设计理念,为企业网的开发设计及使用带来了全新的体验:支持前沿技术:动态缓存、伪静态、静态生成、友好URL、SEO设置等提升网站性能、用户体验、搜索引擎友好度的技术均为Yes!Sun所支持。易于二次开发:采用独创的平台化理念,按需定制项目中的各种元素,如:产品属性、产品相册、新闻列表
性能与维护影响:
- 每个索引都增加写开销(INSERT/UPDATE/DELETE 都要更新索引树)
- 索引占用磁盘和内存,过多索引会拖慢 buffer pool 命中率
- 用
SHOW INDEX FROM table_name查看Cardinality,长期为 0 或极低的索引值得删掉
WHERE 中用了函数或表达式,索引直接失效
像 WHERE YEAR(create_time) = 2023 或 WHERE phone LIKE '%138%'(左侧通配),MySQL 无法用索引定位,因为索引存的是原始值,不是计算结果。
可选替代方案:
- 把函数移到右边:
create_time >= '2023-01-01' AND create_time - 对固定前缀模糊查,用
LIKE '138%',它能走索引;但LIKE '%138'或LIKE '%138%'不行 - 实在要函数查询,考虑生成列(generated column)+ 函数索引(MySQL 5.7+):
ALTER TABLE t ADD COLUMN y INT AS (YEAR(create_time)) STORED, ADD INDEX idx_y(y)
真正容易被忽略的是:索引优化不能只看单条 SQL,得看整体查询模式。一个 (a, b, c) 索引可能让三条不同 WHERE 条件的查询受益,也可能因其中一条查 c 单独出现而完全浪费。上线前用 pt-query-digest 或 slow log 统计真实查询分布,比凭经验猜更可靠。









