Mysql 为什么要有最左前缀的要求,优化器不能自己优化调整顺序吗

比如一个联合索引 index('user_id', 'created_at') ,我写了下面的 SQL 语句

select
    *
from
    tweet
where
    created_at < '2021-11-11'
    and user_id = 1

优化器会把上面的语句优化为下面的语句吗?

select
    *
from
    tweet
where
    user_id = 1
    and created_at < '2021-11-11'
回复
阅读 3.2k
3 个回答

你对左前缀理解错了。

你这种情况是可以用到索引的。

左前缀是指这种情况走不了索引

select
    *
from
    tweet
where
    created_at < '2021-11-11'

而这种情况可以

select
    *
from
    tweet
where
    user_id = 1

因为 user_id 在联合索引的左边。

如果有索引 (a, b, c) 那么 where a, b, cwhere a, bwhere a (where 后的顺序无关,可以随意组合,但是跟出现的字段有关)都是可以走到索引的。但是 where b, c 就不走索引了,因为按照左前缀原则,这里必须要出现 a 才行。

使用如下。

查询条件实际使用
a, b, ca, b, c
a, ca
a, ba, b
aa
b, c

上表中,第二行,a, c 虽然是联合索引(a, b, c) 中有两个字段,但是因为这里没有出现 b,按照做前缀原则就断开了,所以只能使用到 a

注意上文中 where 顺序可以随意组装,比如 a, b, c 你可以写成 a, c, bc, a, b 等,这些都不影响,但是出现的字段必须是上面写到的。

除了 where 外,还有 order。

where a order c 这个就只会用到 (a, b, c) 中的 (a) ,而如果是 where a order b 则能用到 (a, b)

@唯一丶 已经回答的很好了,我再补充一点,那就是即便 MySql 自己优化了,结果也未必说“最优”的。

因为 MySql 的优化策略是“基于成本模型的优化”(Optimizer Cost Model),所以并不会把所有的优化可能都生成并对比一遍。尤其是各版本 MySql 优化器底层实现的还不一样(比如 5.6 和 5.7 的优化器就完全是俩),就导致优化策略也未必相同。所以即便是有优化,也不一定会把你的条件顺序调整成最优的,尤其是当你有多个看似都符合最左前缀原则的索引的情况下。

所以某些情况下需要我们能主动告知 MySql 一种查询方式、使之加入到优化器的对比序列中,也就是需要自己指定好查询条件的顺序。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏