MySQL范围查询优化的场景实例详解


Posted in MySQL onJune 10, 2022

思考题

假设有一张订单表 order,主要包含了主键订单编码 order_no、订单状态 status、提交时间 create_time 等列,并且创建了 status 列索引和 create_time 列索引。此时通过创建时间降序获取状态为 1 的订单编码,以下是具体实现代码:

select order_no from order where status =1 order by create_time desc;

你知道其中的问题所在吗?我们又该如何优化?

解析

status和create_time单独建索引,在查询时只会遍历status索引对数据进行过滤,不会用到create_time列索引,将符合条件的数据返回到server层,在server对数据通过快排算法进行排序,Extra列会出现file sort;

应该利用索引的有序性,在status和create_time列建立联合索引,这样根据status过滤后的数据就是按照create_time排好序的,避免在server层排序

对的,为了避免文件排序的发生。因为查询时我们只能用到status索引,如果要对create_time进行排序,则需要使用文件排序filesort。

filesort是通过相应的排序算法将取得的数据在内存中进行排序,如果内存不够则会使用磁盘文件作为辅助。虽然在一些场景中,filesort并不是特别消耗性能,但是我们可以避免filesort就尽量避免。

阿里巴巴MySQL规范

【推荐】 如果有 order by 的场景,请注意利用索引的有序性。 order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。

正例: where a=? and b=? order by c; 索引: a_b_c

反例: 索引如果存在范围查询, 那么索引有序性无法利用,如: WHERE a>10 ORDER BY b; 索引 a_b 无 法排序

范围查询-基础

讲联合索引,一定要扯最左匹配!

最左匹配 所谓最左原则指的就是如果你的 SQL 语句中用到了联合索引中的最左边的索引,那么这条 SQL 语句就可以利用这个联合索引去进行匹配,值得注意的是,当遇到范围查询(>、<、between、like)就会停止匹配。 假设,我们对(a,b)字段建立一个索引,也就是说,你where后条件为

a = 1
a = 1 and b = 2

是可以匹配索引的。但是要注意的是~你执行

b= 2 and a =1

也是能匹配到索引的,因为Mysql有优化器会自动调整a,b的顺序与索引顺序一致。 相反的,你执行

b = 2

就匹配不到索引了。 而你对(a,b,c,d)建立索引,where后条件为

a = 1 and b = 2 and c > 3 and d = 4

那么,a,b,c三个字段能用到索引,而d就匹配不到。因为遇到了范围查询!

场景一: a = 1 and b = 2 and c = 3

如果sql为

SELECT * FROM table WHERE a = 1 and b = 2 and c = 3;

如何建立索引?

如果此题回答为对(a,b,c)建立索引,那都可以回去等通知了。

此题正确答法是,(a,b,c)或者(c,b,a)或者(b,a,c)都可以,重点要的是将区分度高的字段放在前面,区分度低的字段放后面。像性别、状态这种字段区分度就很低,我们一般放后面。

例如假设区分度由大到小为b,a,c。那么我们就对(b,a,c)建立索引。在执行sql的时候,优化器会 帮我们调整where后a,b,c的顺序,让我们用上索引。

阿里巴巴Java 开发手册

【强制】 在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度。

说明: 索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来确定。

场景二: a > 1 and b = 2

如果sql为

SELECT * FROM table WHERE a > 1 and b = 2;

如何建立索引?

如果此题回答为对(a,b)建立索引,那都可以回去等通知了。

此题正确答法是,对(b,a)建立索引。如果你建立的是(a,b)索引,那么只有a字段能用得上索引,毕竟最左匹配原则遇到范围查询就停止匹配。

如果对(b,a)建立索引那么两个字段都能用上,优化器会帮我们调整where后a,b的顺序,让我们用上索引。

场景三:a > 1 and b = 2 and c > 3

如果sql为

SELECT * FROM `table` WHERE a > 1 and b = 2 and c > 3;

如何建立索引? 此题回答也是不一定,(b,a)或者(b,c)都可以,要结合具体情况具体分析。

拓展一下

SELECT * FROM `table` WHERE a = 1 and b = 2 and c > 3;

怎么建索引?嗯,大家一定都懂了!

场景四: a > 1 ORDER BY b

SELECT * FROM `table` WHERE a = 1 ORDER BY b;

如何建立索引? 这还需要想?一看就是对(a,b)建索引,当a = 1的时候,b相对有序,可以避免再次排序! 那么

SELECT * FROM `table` WHERE a > 1 ORDER BY b;

如何建立索引?

对(a)建立索引,因为a的值是一个范围,这个范围内b值是无序的,没有必要对(a,b)建立索引。

拓展一下

SELECT * FROM `table` WHERE a = 1 AND b = 2 AND c > 3 ORDER BY c;

怎么建索引?

场景五: a IN (1,2,3) and b > 1

SELECT * FROM `table` WHERE a IN (1,2,3) and b > 1;

如何建立索引?

还是对(a,b)建立索引,因为IN在这里可以视为等值引用,不会中止索引匹配,所以还是(a,b)!

拓展一下

SELECT * FROM `table` WHERE a = 1 AND b IN (1,2,3) AND c > 3 ORDER BY c;

如何建立索引?此时c排序是用不到索引的。

总结

尽可能将范围查询转换成“等值”查询,如 “a>1 and a<5 and b>10” 可以写成“a in (1,2,3,4,5) and b > 10”,然后设置索引为 idx(a,b)。

将“等值”条件放在最左边,按最左匹配就可以命中索引。

参考链接1

参考链接2

到此这篇关于MySQL范围查询优化的文章就介绍到这了!

MySQL 相关文章推荐
如何使用Maxwell实时同步mysql数据
Apr 08 MySQL
将图片保存到mysql数据库并展示在前端页面的实现代码
May 02 MySQL
MySQL 分页查询的优化技巧
May 12 MySQL
为什么mysql字段要使用NOT NULL
May 13 MySQL
Mysql数据库索引面试题(程序员基础技能)
May 31 MySQL
mysql 数据插入优化方法之concurrent_insert
Jul 01 MySQL
MySQL定时备份数据库(全库备份)的实现
Sep 25 MySQL
MySQL中的引号和反引号的区别与用法详解
Oct 24 MySQL
MySQL8.0升级的踩坑历险记
Nov 01 MySQL
数据分析数据库ClickHouse在大数据领域应用实践
Apr 03 MySQL
mysql使用 not int 子查询隐含陷阱
Apr 12 MySQL
pt-archiver 主键自增
Apr 26 MySQL
MySQL数据库如何查看表占用空间大小
Jun 10 #MySQL
mysql中关键词exists的用法实例详解
Jun 10 #MySQL
sql注入报错之注入原理实例解析
Jun 10 #MySQL
MySQL如何修改字段类型和字段长度
Jun 10 #MySQL
mysql数据库实现设置字段长度
Jun 10 #MySQL
MySQL优化之慢日志查询
Jun 10 #MySQL
MySql中的json_extract函数处理json字段详情
Jun 05 #MySQL
You might like
初级的用php写的采集程序
2007/03/16 PHP
mayfish 数据入库验证代码
2010/04/30 PHP
解析:使用php mongodb扩展时 需要注意的事项
2013/06/18 PHP
为指定的元素添加遮罩层的示例代码
2014/01/15 Javascript
运用jQuery定时器的原理实现banner图片切换
2014/10/22 Javascript
JavaScript操作cookie类实例
2015/03/31 Javascript
jquery实现简易的移动端验证表单
2015/11/08 Javascript
JS从数组中随机取出几个数组元素的方法
2016/08/02 Javascript
基于js中的原型、继承的一些想法
2016/08/10 Javascript
jQuery实现磁力图片跟随效果完整示例
2016/09/16 Javascript
BootStrap实现带有增删改查功能的表格(DEMO详解)
2016/10/26 Javascript
JavaScript实现简单精致的图片左右无缝滚动效果
2017/03/16 Javascript
Vue2 配置 Axios api 接口调用文件的方法
2017/11/13 Javascript
聊聊JS动画库 Velocity.js的使用
2018/03/13 Javascript
vue中$set的使用(结合在实际应用中遇到的坑)
2018/07/10 Javascript
浅谈webpack构建工具配置和常用插件总结
2020/05/11 Javascript
微信小程序开发(一):服务器获取数据列表渲染操作示例
2020/06/01 Javascript
VSCode插件安装完成后的配置(常用配置)
2020/08/24 Javascript
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
Python计算已经过去多少个周末的方法
2015/07/25 Python
Python中生成Epoch的方法
2017/04/26 Python
python3使用pandas获取股票数据的方法
2018/12/22 Python
python调用API接口实现登陆短信验证
2020/05/10 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
Python3.9.0 a1安装pygame出错解决全过程(小结)
2021/02/02 Python
研修第一天随笔感言
2014/02/15 职场文书
学生党员的自我评价范文
2014/03/01 职场文书
《散步》教学反思
2014/03/02 职场文书
教学质量评估实施方案
2014/03/17 职场文书
工厂采购员岗位职责
2014/04/08 职场文书
爱牙日活动总结
2014/08/29 职场文书
公民授权委托书范本
2014/09/17 职场文书
关于运动会的广播稿
2014/09/22 职场文书
领导干部群众路线剖析材料
2014/10/09 职场文书
2015年班主任个人工作总结
2015/03/31 职场文书
python制作图形界面的2048游戏, 基于tkinter
2021/04/06 Python