MySQL 使用索引扫描进行排序
作者:临时营地 发布时间:2024-01-25 09:25:15
目录
安装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数据库来测试一下
可以看到
书上的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
可以看到
需要注意这一条,在书中使用的的条件是rental_date>'2005-05-25'
WHERE rental_date > '2005-05-25' ORDER BY rental_date, inventory_id
此时无法使用索引排序而是直接全表扫描做了个排序,原因是因为返回数据的条数过多,用索引查询此时已经不划算了
需要注意这里的解释里面的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
对应的执行计划
可以看到使用了索引
无法使用索引扫描的情况
查询条件中包含不同排序方向
SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date = '2005-05-25' ORDER BY inventory_id desc,customer_id asc
索引中两列都是正序,现在order by 中一列正序一列倒序就得二次排序了。
查询条件中引用不在索引中的列
SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date ='2005-08-23 21:01:09' ORDER BY inventory_id ,staff_id
无法组合最左前缀时
SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date ='2005-08-23 21:01:09' ORDER BY customer_id
第一列是查询范围时
SELECT rental_id, staff_id FROM sakila.rental WHERE rental_date > '2005-08-22' ORDER BY inventory_id,customer_id
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中的索引扫描排序,明天我们还将继续介绍其他建立高性能索引的方法,敬请期待,下篇再见!
来源:https://juejin.cn/post/6972047569107189773


猜你喜欢
- 在用sqlAlchemy写web应用的时候,经常会用json进行通信,跟json最接近的对象就是dict,有时候操作dict也会比操作ORM
- 1、jsp前端<%-- Created by IntelliJ IDEA. User: Lenovo Date: 2020/6/19
- 前言Python语言处理字符串、数组类的问题时有一定概率需要使用切片方法,比如:Leetcode_5。学习官方解法时发现切片的索引可以超出字
- 一. 图片懒加载的目的大型网站如常用的淘宝,京东等页面,需要展示大量的商品图片信息,如果打开网页时让所有图片一次性加载完成,需要处理很多次网
- 下面写一个给大家做参考啊 create procedure sp_find(pfind varchar(500) BEGIN DECLAR
- 原文地址第一次翻译文章,请各路人士多多指教!类型和接口因为映射建设在类型的基础之上,首先我们对类型进行全新的介绍。go是一个静态性语言,每个
- 一、什么是NumPyNumpy--Numerical Python,是一个基于Python的可以存储和处理大型矩阵的库。几乎是Python
- 1. 获取系统当前时间MySQL 版本为 5.7,详细的时间函数可以参考 MySQL 官方文档 在这里1.1. 获取 YYYY-MM-DD
- cs页面调用代码: public int TotalPage = 0; public int PageCurrent = 1; public
- 听说安全地断开Connection连接的记录集可以提高ASP的运行速度,请问如何实现?很多人会将一个Connection对象存储在Appli
- python中使用.py配置文件 一、格式:创建一个config.py文件在文件中加配置:DEBUG=Truedm_connect = {
- 一、需求说明在Python程序的开发过程中,一些程序需要获取函数或程序的开始时间、结束时间和时间间隔等内容用来分析和处理内容二、需求分析涉及
- FCKeditor的样式设置涉及到了两个文件,一个是你定义好的样式表文件.css,另一个是告诉fck样式表如何使用的xml文件,两个文件确一
- Django 中,html 页面通过 form 标签来传递表单数据。对于复选框信息,即 checkbox 类型,点击 submit 后,数据
- 本文实例讲述了Python字符串、列表、元组、字典、集合。分享给大家供大家参考,具体如下:附加:python的很多编译器提供了代码补全功能,
- 目录1. 折线图概述1.1什么是折线图?1.2折线图使用场景1.3绘制折线图步骤1.4案例展示2. 折线2D属性2.1linestyle:折
- 之前使用bootstrap写了一个报表表格,最近突然找到我,说让我看看能不能将表格的表头和第一列进行固定,这样的话方便查看数据,于是,我开始
- 一、建立文件,保存数据1.使用python中内置的open函数 打开txt文件#mode 模式#w 只能操作写入 r 只能读取 a 向文件追
- 可以把本功能写成一个函数,函数的处理过程描述如下:首先调用adodb.connection对象中的openSchema函数,这样会得到一个R
- 本文实例讲述了PHP接口多继承及tarits实现多继承效果的方法。分享给大家供大家参考,具体如下:接口多继承在PHP的面向对象中,接口可以继