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 相关文章推荐
分析MySQL抛出异常的几种常见解决方式
May 18 MySQL
带你学习MySQL执行计划
May 31 MySQL
zabbix监控mysql的实例方法
Jun 02 MySQL
解析MySQL binlog
Jun 11 MySQL
浅谈MySQL之浅入深出页原理
Jun 23 MySQL
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
Jul 01 MySQL
MySQL系列之八 MySQL服务器变量
Jul 02 MySQL
MySQL数据库中varchar类型的数字比较大小的方法
Nov 17 MySQL
MySQL优化及索引解析
Mar 17 MySQL
利用JuiceFS使MySQL 备份验证性能提升 10 倍
Mar 17 MySQL
MySQL外键约束(Foreign Key)案例详解
Jun 28 MySQL
delete in子查询不走索引问题分析
Jul 07 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中的string类型使用说明
2010/07/27 PHP
php daddslashes()和 saddslashes()有哪些区别分析
2012/10/26 PHP
JS 文件传参及处理技巧分析
2010/05/13 Javascript
javascript中的作用域scope介绍
2010/12/28 Javascript
模仿百度三维地图的js数据分享
2011/05/12 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
Node.js程序中的本地文件操作用法小结
2016/03/06 Javascript
创建一般js对象的几种方式
2017/01/19 Javascript
JavaScript如何获取到导航条中HTTP信息
2017/10/10 Javascript
使用Node搭建reactSSR服务端渲染架构
2018/08/30 Javascript
使用xampp将angular项目运行在web服务器的教程
2019/09/16 Javascript
原生js实现贪食蛇小游戏的思路详解
2019/11/26 Javascript
Threejs实现滴滴官网首页地球动画功能
2020/07/13 Javascript
在HTML中使用JavaScript的两种方法
2020/12/24 Javascript
[03:17]DOTA2英雄基础教程 剧毒术士
2013/12/12 DOTA
[03:21]辉夜杯主赛事 12月25日TOP5
2015/12/26 DOTA
利用python微信库itchat实现微信自动回复功能
2017/05/18 Python
Python实现字典的遍历与排序功能示例
2017/12/23 Python
Python爬虫之pandas基本安装与使用方法示例
2018/08/08 Python
pygame实现简易飞机大战
2018/09/11 Python
python对于requests的封装方法详解
2019/01/03 Python
python实时获取外部程序输出结果的方法
2019/01/12 Python
Python多线程同步---文件读写控制方法
2019/02/12 Python
简单了解python代码优化小技巧
2019/07/08 Python
python误差棒图errorbar()函数实例解析
2020/02/11 Python
python中提高pip install速度
2020/02/14 Python
Python基于requests库爬取网站信息
2020/03/02 Python
python用opencv完成图像分割并进行目标物的提取
2020/05/25 Python
美国标志性加大尺码时装品牌:Ashley Stewart
2016/12/15 全球购物
意大利香水和彩妆护肤品购物网站:Ditano
2017/08/13 全球购物
教师节倡议书
2014/08/30 职场文书
党的群众路线教育实践活动对照检查材料思想汇报(党员篇)
2014/09/25 职场文书
企业工会工作总结2015
2015/05/13 职场文书
python数据可视化JupyterLab实用扩展程序Mito
2021/11/20 Python
python中的sys模块和os模块
2022/03/20 Python
Elasticsearch 基本查询和组合查询
2022/04/19 Python