MySQL 使用索引扫描进行排序


Posted in MySQL onJune 20, 2021
目录
  • 安装sakila
  • 索引扫描排序
  • 表结构
  • 可以使用索引扫描来做排序的情况
    • 补足前导列
    • order by 中只包含一种排序
  • 无法使用索引扫描的情况
    • 查询条件中包含不同排序方向
    • 查询条件中引用不在索引中的列
    • 无法组合最左前缀时
    • 第一列是查询范围时
    • where中有多个等于条件
  • 总结

 

安装sakila

我们将会使用MySQL示例数据库sakila来进行sql的演示和讲解 dev.mysql.com/doc/sakila/…

 

索引扫描排序

MySQL有两种方式可以生成有序的结果:通过排序操作?或者按索引顺序扫描?如果EXPLAIN出来的type列的值为“index”,则说明MySQL使用了索引扫描来做排序。
扫描索引本身是很快的,因为只需要从一条索引记录移动到紧接着的下一条记录。但如果索引不能覆盖查询所需的全部列,那就不得不每扫描一条索引记录就都回表查询一次对应的行。这基本上都是随机I/O,因此按索引顺序读取数据的速度通常要比顺序地全表扫描慢,尤其是在IO密集型的工作负载时。此时可能就会用全表扫描而不是按索引查找了。
如果可能,设计索引时应该尽可能地同时满足排序和查找行。
只有当索引的列顺序和0RDER BY子句的顺序完全一致,并且所有列的排序方向(倒序或正序)都一样时,MySQL才能够使用索引来对结果做排序。如果查询需要关联多张表,则只有当ORDER BY子句引用的字段全部为第一个表时,才能使用索引做排序。ORDER BY子句和查找型查询的限制是一样的:需要满足索引的最左前缀的要求?否则,MySQL都需要执行排序操作(filesort),而无法利用索引排序。

 

表结构

我们将使用rental这个表来进行讲解

CREATE TABLE `rental` (
  
  UNIQUE KEY `rental_date` (`rental_date`,`inventory_id`,`customer_id`),
  KEY `idx_fk_inventory_id` (`inventory_id`),
  KEY `idx_fk_customer_id` (`customer_id`),
  KEY `idx_fk_staff_id` (`staff_id`),
  
) ENGINE=InnoDB AUTO_INCREMENT=16050 DEFAULT CHARSET=utf8mb4;

查看Extra 中是否出现Using filesort(MySQL中无法利用索引完成的排序操作称为“文件排序”)当我们试图对一个没有索引的字段进行排序时,就是filesort。虽然里面有个file,但它跟文件没有任何关系,实际上是内部的一个快速排序

 

可以使用索引扫描来做排序的情况

 

补足前导列

有一种情况下ORDER BY子句可以不满足索引的最左前缀的要求,就是前导列为常量的时候。如果WHERE子句或者JOIN子句中对这些列指定了常量,就可以“弥补”索引的不足。 我们使用Sakila数据库来测试一下

可以看到

MySQL 使用索引扫描进行排序

书上的Extra写的是Using where,而我执行的时候是Using index condition ,原因是高性能MySQL中使用的版本是5.5,5.6版本中的索引条件推送(index condition pushdown)还处于未正式发布阶段呢。这里没有filesort的原因是因为有个rental_date = '2005-05-25'的常量条件,相当于将索引的第一列补足了,这样就符合了索引的最左前缀要求。

 

order by 中只包含一种排序

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date = '2005-05-25' ORDER BY  inventory_id desc

可以看到

MySQL 使用索引扫描进行排序

需要注意这一条,在书中使用的的条件是rental_date>'2005-05-25'

WHERE rental_date > '2005-05-25' ORDER BY rental_date, inventory_id

此时无法使用索引排序而是直接全表扫描做了个排序,原因是因为返回数据的条数过多,用索引查询此时已经不划算了

MySQL 使用索引扫描进行排序

需要注意这里的解释里面的rows并不准确,只是一个估算值,实际上按这个条件查询有16036条数据 要想解决这个问题,就需要加上limit

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date > '2005-05-25' ORDER BY rental_date, inventory_id limit 0,10

对应的执行计划

MySQL 使用索引扫描进行排序

可以看到使用了索引

 

无法使用索引扫描的情况

 

查询条件中包含不同排序方向

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date = '2005-05-25' ORDER BY  inventory_id desc,customer_id asc

索引中两列都是正序,现在order by 中一列正序一列倒序就得二次排序了。

MySQL 使用索引扫描进行排序

 

查询条件中引用不在索引中的列

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date ='2005-08-23 21:01:09' ORDER BY  inventory_id ,staff_id

MySQL 使用索引扫描进行排序

 

无法组合最左前缀时

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date ='2005-08-23 21:01:09' ORDER BY  customer_id

MySQL 使用索引扫描进行排序

 

第一列是查询范围时

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date > '2005-08-22' ORDER BY  inventory_id,customer_id

MySQL 使用索引扫描进行排序

 

where中有多个等于条件

SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date ='2005-08-23 21:01:09' and inventory_id in(1,2)  ORDER BY  customer_id

简单来说就是不符合索引最左前缀的就会进行一次排序。

MySQL 使用索引扫描进行排序

 

总结

今天我们讲解了MySQL中的索引扫描排序,明天我们还将继续介绍其他建立高性能索引的方法,敬请期待,下篇再见!

以上就是MySQL 索引扫描的简单使用的详细内容,更多关于MySQL 索引扫描排序的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
mysql查询的控制语句图文详解
Apr 11 MySQL
MySQL命令行操作时的编码问题详解
Apr 14 MySQL
mysql 8.0.24 安装配置方法图文教程
May 12 MySQL
mysql升级到5.7时,wordpress导数据报错1067的问题
May 27 MySQL
MySQL5.7并行复制原理及实现
Jun 03 MySQL
mysql 带多个条件的查询方式
Jun 05 MySQL
安装配置mysql及Navicat prenium的详细流程
Jun 10 MySQL
为什么MySQL 删除表数据 磁盘空间还一直被占用
Oct 16 MySQL
mysql timestamp比较查询遇到的坑及解决
Nov 27 MySQL
mysql分组后合并显示一个字段的多条数据方式
Jan 22 MySQL
分享MySQL常用 内核 Debug 几种常见方法
Mar 17 MySQL
MySQL主从切换的超详细步骤
Jun 28 MySQL
新手入门Mysql--概念
mysql获取指定时间段中所有日期或月份的语句(不设存储过程,不加表)
MySQL REVOKE实现删除用户权限
Jun 18 #MySQL
MySQL GRANT用户授权的实现
Jun 18 #MySQL
浅谈MySQL user权限表
Jun 18 #MySQL
解决mysql模糊查询索引失效问题的几种方法
Jun 18 #MySQL
MySQL 亿级数据导入导出及迁移笔记
You might like
Windows7下PHP开发环境安装配置图文方法
2010/05/20 PHP
PHP5中使用PDO连接数据库的方法
2010/08/01 PHP
确保Laravel网站不会被嵌入到其他站点中的方法
2019/10/18 PHP
php pdo连接数据库操作示例
2019/11/18 PHP
Js冒泡事件详解及阻止示例
2014/03/21 Javascript
jQuery实现的导航条切换可显示隐藏
2014/10/22 Javascript
JS实现简单路由器功能的方法
2015/05/27 Javascript
浅谈javascript中基本包装类型
2015/06/03 Javascript
JSONP和批量操作功能的实现方法
2016/08/21 Javascript
ES2015 Symbol 一种绝不重复的值
2016/12/25 Javascript
jQuery中DOM节点的删除方法总结(超全面)
2017/01/22 Javascript
JavaScript调试之console.log调试的一个小技巧分享
2017/08/07 Javascript
AngularJS 表单验证手机号的实例(非必填)
2017/11/12 Javascript
Vue实现动态创建和删除数据的方法
2018/03/17 Javascript
vue 父组件给子组件传值子组件给父组件传值的实例代码
2019/04/15 Javascript
3分钟读懂移动端rem使用方法(推荐)
2019/05/06 Javascript
EasyUI 数据表格datagrid列自适应内容宽度的实现
2019/07/18 Javascript
js实现蒙版效果
2020/01/11 Javascript
[02:05]2014DOTA2西雅图邀请赛 老队长全明星大猜想谁不服就按进显示器
2014/07/08 DOTA
Python中的模块导入和读取键盘输入的方法
2015/10/16 Python
Python实现自定义顺序、排列写入数据到Excel的方法
2018/04/23 Python
python排序函数sort()与sorted()的区别
2018/09/18 Python
python 实现selenium断言和验证的方法
2019/02/13 Python
Python socket处理client连接过程解析
2020/03/18 Python
Html5写一个简单的俄罗斯方块小游戏
2019/12/03 HTML / CSS
施华洛世奇天猫官方旗舰店:SWAROVSKI
2017/04/17 全球购物
法国二手MacBook销售网站:Okamac
2019/03/18 全球购物
Genny意大利官网:意大利高级时装品牌
2020/04/15 全球购物
Linux上比较文件的命令都有哪些
2013/09/28 面试题
自我鉴定的范文
2013/10/03 职场文书
公司活动邀请函
2014/01/24 职场文书
纪念9.18事变演讲稿
2014/09/14 职场文书
2014年祖国生日寄语
2014/09/19 职场文书
中学生打架检讨书之500字
2019/08/06 职场文书
微信小程序结合ThinkPHP5授权登陆后获取手机号
2021/11/23 PHP
Windows11 Insider Preview Build 25206今日发布 更新内容汇总
2022/09/23 数码科技