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. 考虑索引覆盖 :如果只需查询 ab,确保索引包含所有需要的列(如 INDEX idx_a_b (a, b))。

总结

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

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

相关推荐
只说证事2 分钟前
会计岗位向管理会计升级,最该补哪些数据分析技能
数据库·数据挖掘·数据分析
a95114164240 分钟前
如何加固SQL集群防注入_实施网络层访问控制策略
jvm·数据库·python
2401_835956811 小时前
mysql处理大量更新场景_InnoDB MVCC与MyISAM对比
jvm·数据库·python
m0_748920361 小时前
Oracle默认端口被占用如何连接_修改端口号操作教程
jvm·数据库·python
qq_342295821 小时前
Redis怎样按照距离远近排序展示_通过GEORADIUS的ASC参数进行Geo排序
jvm·数据库·python
2201_761040591 小时前
C#比较两个二进制文件的差异 C#如何实现一个二进制diff工具
jvm·数据库·python
Polar__Star1 小时前
SQL中如何实现特定顺序的查询:CASE WHEN自定义排序
jvm·数据库·python
一只大袋鼠2 小时前
MyBatis 入门详细实战教程(一):从环境搭建到查询运行
java·开发语言·数据库·mysql·mybatis
u0109147602 小时前
mysql如何配置监听IP_mysql bind-address多地址设置
jvm·数据库·python
java资料站2 小时前
MySQL 8.0.45 完整mysqld_safe启动
数据库·mysql