MySQL 查询索引最左前缀原则,如果是(a,b)的联合索引,WHERE b = ? AND a = ?会走索引吗

从SQL原本的理解上,不会走联合索引

但是MySQL有优化器,会针对 WHERE b = ? AND a = ? 这种特定情况进行优化,使其走联合索引(a,b)

  • 优化器的版本要求 MySQL >= 5.7
  • 如果其中有唯一索引,比如a是唯一索引,这里就不会走联合索引了,会走唯一索引,这样更快

在 MySQL 中,联合索引 (a, b) 的查询顺序必须遵循"最左前缀原则" 。如果查询条件是 WHERE b = ? AND a = ?,虽然逻辑上等价于 WHERE a = ? AND b = ?,但能否利用联合索引取决于实际书写顺序和优化器的处理。以下是详细分析:


1. 联合索引 (a, b) 的存储结构

  • 索引是按照 (a, b) 的顺序存储的,即先按 a 排序,a 相同的情况下再按 b 排序。
  • 最左前缀原则:查询必须从索引的最左列开始,才能有效利用索引。

2. WHERE b = ? AND a = ? 的情况

(1) 能否利用索引?

  • 严格来说,不能直接利用 (a, b) 索引 ,因为查询条件没有从 a 开始。
  • 但 MySQL 优化器可能会自动重写条件 :
    • 如果优化器将 WHERE b = ? AND a = ? 重写为 WHERE a = ? AND b = ?,则可以利用索引。
    • 如果未重写,则无法利用索引,可能导致全表扫描。

(2) 实验验证

表结构与索引
复制代码

sql

复制代码
`CREATE TABLE test (
    id INT PRIMARY KEY,
    a INT,
    b INT,
    INDEX idx_a_b (a, b)
);`
查询 1:WHERE a = 1 AND b = 2(符合最左前缀)
复制代码

sql

复制代码
`EXPLAIN SELECT * FROM test WHERE a = 1 AND b = 2;`
  • 结果 :会使用 idx_a_b 索引(key: idx_a_b)。
查询 2:WHERE b = 2 AND a = 1(条件顺序相反)
复制代码

sql

复制代码
`EXPLAIN SELECT * FROM test WHERE b = 2 AND a = 1;`
  • 结果 :
    • MySQL 5.7+ 和 8.0 :优化器会自动重写为 WHERE a = 1 AND b = 2,仍然使用 idx_a_b。
    • 旧版本 MySQL:可能无法利用索引,导致全表扫描。

3. 关键结论

  1. 索引顺序是物理存储顺序,查询必须从最左列开始才能高效利用。
  2. MySQL 优化器会尝试重写条件 ,因此 WHERE b = ? AND a = ? 在大多数现代版本中仍能利用 (a, b) 索引。
  3. 但依赖优化器不可靠 ,建议显式写成 WHERE a = ? AND b = ? 以确保索引被使用。

4. 其他相关场景

(1) 只查询 b 列(WHERE b = ?)

  • 无法利用 (a, b) 索引 ,因为缺少 a 的条件。
  • 解决方法:
    • 单独为 b 创建索引。
    • 使用覆盖索引(如 (b, a))。

(2) 范围查询 + 精确匹配

  • WHERE a = 1 AND b > 10:可以利用 (a, b) 索引(先定位 a = 1,再在范围内找 b > 10)。
  • WHERE a > 1 AND b = 10:只能用到 a 的部分索引 ,因为 b 的条件在范围查询后无法高效过滤。

5. 最佳实践

  1. 遵循最左前缀原则:查询条件从索引的最左列开始。
  2. 显式书写条件顺序 :避免依赖优化器重写,直接写 WHERE a = ? AND b = ?。
  3. 使用 EXPLAIN 验证:检查执行计划是否真的用了索引。
  4. 考虑索引覆盖 :如果只需查询 a 和 b,确保索引包含所有需要的列(如 INDEX idx_a_b (a, b))。

总结

  • WHERE b = ? AND a = ? 在现代 MySQL 中通常能利用 (a, b) 索引(因优化器重写)。
  • 但最安全的方式是显式写成 WHERE a = ? AND b = ?。
  • 如果查询不符合最左前缀(如仅 WHERE b = ?),则无法利用 (a, b) 索引。

建议通过 EXPLAIN 实际验证查询计划!

相关推荐
草莓熊Lotso25 分钟前
【C++ 基于微服务的即时通讯系统】etcd + brpc 从安装到服务注册发现全链路实战
网络·数据库·c++·redis·微服务·etcd
Lethehong6 小时前
Oracle 加个字段,目标库就报错?KFS 用“先拆后组“打通异构 DDL
数据库·oracle
Web极客码6 小时前
锁定真正的磁盘卡顿:我用 OpenCode 配合 eBPF 诊断 NVMe 队列深度延迟与 I/O 写放大
数据库·oracle
cspttty7 小时前
2027用户研究求职准备:应用统计学如何补齐研究设计与业务表达
大数据·数据库
roman_日积跬步-终至千里8 小时前
【数据Agent论文·查询与语义|05】Spider:为什么换一个数据库,模型就不会查了?
数据库·数据分析
猫咪很可爱8 小时前
Oracle RAC 启动失败排查:私网通信与内核参数优化实战
运维·数据库·oracle
XLYcmy9 小时前
《数字经济赋能城市低碳治理的路径研究检索报告》审阅与修改指导意见——基于完整检索报告体例的完整性诊断、学术规范核查与方法论纠偏 上
数据库·ai·chatgpt·文心一言·检索·知网·豆包
泡海椒9 小时前
JQuick-SQL 快速开始:注册内存表并执行查询
数据库·windows·sql
ss2739 小时前
PG实战笔记 | 09 PostgreSQL psql客户端基本操作
数据库·笔记·postgresql
电商API_180079052479 小时前
反向海淘多币种结算:汇率该在哪个时点被冻结
java·开发语言·数据库·跨境电商·1688 api