MySQL除了order by可以生成有序结果,索引也可以!

举报
阿柠 发表于 2022/10/09 15:17:27 2022/10/09
【摘要】 使用索引扫描来做排序MySQL有两种方式可以生成有序的结果:通过排序操作;或者按照索引顺序扫描;如果explain出来的type列的值是index,则说明mysql使用了索引扫描来做排序(不要和extra列的using index高混淆了)扫描索引本身是很快的,因为只需要从一条索引记录移动到紧挨着的下一条记录。但是如果索引不能覆盖查询所需的全部列,那就不得不每扫描一条索引记录就都回表查询一...

使用索引扫描来做排序

MySQL有两种方式可以生成有序的结果:通过排序操作;或者按照索引顺序扫描;如果explain出来的type列的值是index,则说明mysql使用了索引扫描来做排序(不要和extra列的using index高混淆了)

扫描索引本身是很快的,因为只需要从一条索引记录移动到紧挨着的下一条记录。但是如果索引不能覆盖查询所需的全部列,那就不得不每扫描一条索引记录就都回表查询一次对应的行。这基本上都是随机IO,因此按索引顺序读取数据的速度通常要比顺序的全表扫描慢,尤其是在IO密集型的工作负载时。

只有当索引的列顺序和order by子句顺序完全一致,并且所有列的排序方向都一样时,MySQL才能用索引来对结果做排序。如果查询需要关联多张表,则只有当order by子句引用的字段全为第一个表时,才能使用索引做排序。order by子句和查找型查询的限制是一样的:需要满足索引的最左前缀的要求;否则MySQL都需要执行排序操作,而无法利用索引排序。

当然有一种情况下order by子句可以不满足索引的最左前缀的要求,就是前导列为常量的时候。如果where子句或者join子句中对这些列指定了常量,就可以弥补索引的不足。

比如说我们举一个例子:

对于下面这样一个表结构:

create table 表名(
。。。。
key lizi (date,id1,id2),
。。。。
)

然后对于下面这个查询语句:

select 内容
fromwhere date  = 11
order by id1,id2;

这种查询,MySQL就可以使用lizi这个索引为查询排序。当然,我们可以看到即使order by这个子句是不满足最左前缀的要求的,但是没关系呀,索引的第一列date的被指定为了一个常数呀。

你再比如像下面这样:

where date = 常数
order by id1;

你像上面这个还是可以使用索引排序的,第一列常数,然后再索引的最左前缀嘛。

你再在比如说下面这个:

where date >日期 order by  date,id1;

这个就也能用索引排序,order by使用的两列就是索引的最左前缀。

:car: 都讲了这么老半天的能用索引排序的,那么下面我就来说说这个不能使用索引排序的查询。

  • 使用两种不同的排序方向,即使索引列都是正序排序的。

    where date = 常数 order by id1 desc ,id2  asc;
    
  • order by 子句中引用了一个不在索引中的列

    where  date  = 常数 order by id1 ,id3;
    
  • where和order by 中的列无法组合成索引的最左前缀

    where date = 常数 order by id2;
    
  • 查询的第一列不是常数,而是范围,就也不能用最左前缀了。

    where date > 常数 order by id1,id2;
    
  • id1这一列有多个等于条件,对于排序也是范围查询,不能使用索引排序

    where date = 常数 AND id1 IN1,2order by id2;
    
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。