【业务学习】关于MySQL order by limit 走错索引的探讨

逻辑极昼
• 阅读 6625

Grape


描述

今天在跑脚本的时候发现了几条慢查询,根据之前的经验实属不应该,后来经过查找资料和分析出来结果,在这里简单记录一下。

首先,我的sql是这个样子:

select `id` from `xxx` force index(idx_d_t)  where `date` = '2019-09-11' AND `time_flag` < '20190911220000' order by  id asc;

索引是下边这个样子:

KEY `inx_t_d` (`date`,`time_flag`);

按照我之前的理解这条sql是可以走这个索引的,但是他没有,他选择了主键索引。

分析

看到这是个慢查询,我起手一个explain,结果如下:

【业务学习】关于MySQL order by limit 走错索引的探讨

看到这个结果我肯定不服啊,为什么是走的主键索引,因此开始了百度谷歌之旅。
刚开始我找到了一个自认为比较正确的方法,在某度上找了一篇文章说orderby之前有范围查找的会走orderby之后的索引,反之走orderby之前的索引,我试了一下,哎,不错,我把范围查询改成了等值查询,是走了我的索引了,但是我看了一眼行数,一脸懵逼,为什么这么多行?这不是我想要的

【业务学习】关于MySQL order by limit 走错索引的探讨

然后我profiling(大家可以自行百度)查了下时间,发现Creating sort index这哥们占用了九成的时间,这时候我敏锐的察觉到了这个排序有问题,(该吃饭了)不行,继续查!
继续查,上某哥,哎你别说,某哥大法还是好,终于找到了一个大佬的分析,具体是什么原因呢?

首次,我强制走我的联合索引看下情况:

【业务学习】关于MySQL order by limit 走错索引的探讨

看到上图会发现有个差别就是Using filesort这玩意儿,这玩意儿是个什么东西呢?简单的说filesort 是通过相应的排序算法将取得的数据在内存中进行排序。俗话说有对比才有伤害,抓到敌人的小辫子就接近了胜利,我们继续看。

fliesort有两种排序方式:

  1. 双路排序:首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在 sort buffer 中进行排序。
  2. 单路排序:是一次性取出满足条件行的所有字段,然后在 sort buffer 中进行排序。

什么时候用到这两种呢?MySQL 主要通过比较所设定的系统参数 max_length_for_sort_data 的大小和 Query 语句所取出的字段类型大小总和来判定需要使用哪一种排序算法。如果 max_length_for_sort_data 更大,则使用第二种优化后的算法,反之使用第一种算法。很显然应该尽可能让 MySQL 选择使用第二种单路算法来进行排序。这样可以减少大量的随机 IO 操作,很大幅度地提高排序工作的效率。

上文分析的排序时间过长很可能就和这个有关系了,继续查资料分析,问题的关键就在于为什么会filesort。

结论

在执行语句的时候,因为数据量较大,MySQL优化器认为走联合索引不好,默认选择了第一个更慢的执行计划,它的理由是走主键索引不需要内存排序,候选的 idx_d_t被淘汰。优化器认为主键索引不用排序比联合索引要好,所以导致了这种情况,
那我们该怎么做,在这里我只列出我的解决方法,他认为主键更好,那么我们就给他更好的,我们更改idx_d_t这个索引,由date,time_flag改成,id,date,time_flag,这样就解决问题了。
如图:

【业务学习】关于MySQL order by limit 走错索引的探讨

最后总结一下,就是优化器会尽量避免走file_sort,这样可能会导致一些问题。

以上分析若有差错,还望不吝指教!感谢。

参考文章:

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Stella981 Stella981
4年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Easter79 Easter79
4年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
MySQL ORDER BY主键id加LIMIT限制走错索引
背景及现象report\_product\_sales\_data表数据量2800万;经测试,在当前数据量情况下,orderby主键id,limit最大到49的时候可以用到索引report\_product\_sales\_data\_hq\_code\_orgz\_id\_index,大于49时就走PRIMARY主键索引。
Stella981 Stella981
4年前
Bypass ngx_lua_waf SQL注入防御(多姿势)
0x00前言ngx\_lua\_waf是一款基于ngx\_lua的web应用防火墙,使用简单,高性能、轻量级。默认防御规则在wafconf目录中,摘录几条核心的SQL注入防御规则:select.(from|limit)(?:(union(.?)select))(?:from\Winformation_schema\W)这边
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这