
WHERE 条件里用了多个字段,为什么联合索引没生效?
联合索引不是“只要字段都在索引里就一定走”,它严格遵循最左前缀原则。比如建了 INDEX idx_a_b_c (a, b, c),以下查询能用上索引:
WHERE a = 1WHERE a = 1 AND b = 2WHERE a = 1 AND b = 2 AND c = 3
但这些不会用全索引(甚至可能不走索引):
-
WHERE b = 2—— 缺少a,跳过最左列,索引失效 -
WHERE a = 1 AND c = 3——b被跳过,c无法命中 -
WHERE a > 1 AND b = 2 AND c = 3—— 范围查询后,右边字段不再用于索引查找(c不参与索引定位)
JOIN 多表时,ON 条件字段怎么配索引才不拖慢?
MySQL 的 JOIN 是单边驱动的:驱动表(通常是 LEFT JOIN 左边或小结果集表)先扫描,被驱动表靠 ON 条件匹配。关键点是——被驱动表的 ON 字段必须有索引,否则就是全表扫描。
- 如果写
SELECT * FROM orders o JOIN users u ON o.user_id = u.id,且users是被驱动表,那u.id必须有索引(主键通常已满足) - 但如果 ON 是
o.user_id = u.id AND u.status = 'active',而u.status没索引,MySQL 可能放弃使用u.id索引,改走全表扫描 - 更常见的是反模式:
JOIN product p ON o.product_code = p.code,但p.code没索引 → 每次匹配都扫全表product
验证方法:加 EXPLAIN 看 type 列,ALL 或 index(非唯一索引扫描)基本说明有问题。
ORDER BY + LIMIT 和多列关联一起用,为什么排序还是慢?
当查询含 JOIN、WHERE、ORDER BY、LIMIT 时,MySQL 很可能先 JOIN 出全部结果,再排序分页——数据量一大就卡死。根本原因:排序字段不在驱动表,或没覆盖索引。
- 例如
SELECT o.id, u.name FROM orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'paid' ORDER BY u.created_at DESC LIMIT 10,u.created_at在被驱动表,MySQL 往往无法利用索引完成排序 - 解决方案优先级:① 把排序字段挪到驱动表;② 在被驱动表上建包含
ON字段 + 排序字段的联合索引,如INDEX idx_user_id_created (user_id, created_at)(注意顺序!);③ 避免在 JOIN 后对非驱动表字段排序 - 注意:即使加了索引,如果
WHERE过滤后结果集仍很大,ORDER BY仍可能触发 filesort
复合索引字段顺序到底该怎么排?
顺序不是按 SELECT 出现顺序,也不是按表中定义顺序,而是按「过滤强度 + 查询模式」定。三个硬约束:
- 等值查询字段放最左(如
status = 'paid'),因为能精确锁定索引段 - 范围查询字段(
>、BETWEEN、LIKE 'abc%')只能放在等值字段之后,且后面字段无法用于索引查找 - 排序/分组字段(
ORDER BY、GROUP BY)尽量紧接在等值字段后,才能避免 filesort
举例:要支持 WHERE shop_id = 123 AND status IN ('shipped', 'delivered') AND created_at > '2024-01-01' ORDER BY updated_at DESC,最优索引是 INDEX idx_shop_status_created_updated (shop_id, status, created_at, updated_at)。把 updated_at 放最后,是因为前面已有范围条件(created_at > ...),它无法用于查找,但可用于排序。
实际中,一个表上不要堆太多复合索引;每多一个索引,INSERT/UPDATE 就多一份维护成本,而且优化器也可能选错索引。










