MySQL之SQL分析三部曲实际案例(三)--limit的陷阱

附上MySQL之SQL分析三部曲地址http://blog.itpub.net/29510932/viewspace-1709732/

姐妹篇http://blog.itpub.net/29510932/viewspace-1732876/ (其实是难兄难弟篇)

-------------------------------------------------------------------------------------------------正文---------------------------------------------------------------------------------------------------------------

由于是生产环境下进行的,截图和SQL都隐去了一些信息

背景:有用户在抱怨生产系统上,某一个Web的页面太慢,忍无可忍
问题分析过程:略
问题聚焦:最终确定是某一个SQL语句太慢,查询时间用了4s(慢查询日志给出的信息)

点击(此处)折叠或打开

点击(此处)折叠或打开

  1. select *
  2. from tom
  3. inner join toa on tom.order_id=toa.order_id
  4. left join tov on tom.order_id=tov.order_id
  5. left join fo on tom.sale_type=2 and fo.order_id=tom.order_id
  6. WHERE(tom.pay_time>='2015-06-23 11:45:55.869' and tom.pay_time<='2015-07-23 11:45:55.869' and tom.shop_idin(1,2) and tom.buyer_nick='你们真是够了23333')
  7. order by tom.pay_time desc
  8. limit 0,20

SQL分析三部曲之一:explain,结果如下图

OMG,明显有pay_tim和shop_id的联合索引,为什么要用pay_time的单列索引,简单验证下联合索引的执行计划

和案例一非常相似的情形,明明可以使用联合索引的地方,却使用了单列的索引,导致了预估的行数非常之高,那么,会和案例一一样是因为统计信息的不全,导致了错误的执行计划么?

PS:案例一的情况,在没有进行任何数据库层面改动的前提下,仅仅是睡了个午觉,执行计划就变回正确的了,所以当时候判定为统计信息的问题。

然而残酷的事实就是:不管analyze table多少次,执行计划也没有改变,(没有optimize table的权限...)

SQL分析三部曲之三:optimizer_trace,操作过程略,部分结果如图

可以看到和案例一类似,由于limit的存在,导致执行计划发生了变化,但是和案例一不同的是,这个SQL里面,limit和row_estimate的值相差的非常远!

PS:案例一中为40和51

值得注意的是,limit的数量也会影响到执行计划的选择,比如说,limit的行数小于执行计划的row_estimate的时候,优化器会认为当前执行计划搜索出了太多的结果,进行了无谓的磁盘IO,所以会重新考虑执行计划。

在本例中,由于在limit之前带上了order by,而且order by的列本身还是具备索引,因此,在优化器的判断逻辑中就出现了如下的一种情形:可以使用pay_time索引列,从尾部开始读取数据,然后取出前20行结果组装成结果集。所以优化器重新选择了使用pay_time的单列索引作为执行计划(这也是其他的索引均显示了“not_applicable”的原因)。

案例一的真相还原:为什么睡个午觉,执行计划就正常了?
由于在某个时间点重新统计了表的信息,行数的估计值产生了变化,导致limit和row_estimate的大小关系发生了变化,结果就是row_estimate的值小于了limit,自然也就不会存在rechecking_index_usage了。

在这里简单的修改了几处条件来验证之前的结论,
条件修改一:使用ignore index(idx_pay_time)
预计:如果order by的列本身并没有索引,那么在recheck里面也就没有其他的执行计划可选了,最终应该选择range_scan中的联合索引

从执行计划中可以看到idx_pay_time已经ignore了,最终执行计划选择range_scan中的联合索引

看看trace的信息

在recheck中根本就没有可选索引,所以执行计划并没有改变

条件修改二:增加limit数量直至超过row_estimate
预计:不会有recheck,执行计划采用联合索引
查看explain和trace

recheck无内容

条件修改三:去掉order by
预计:recheck无可选条件,使用联合索引

意外的收获:采用其他的索引列进行order by(仅以此献给能坚持看完这么长的内容的米娜~)
预计:执行计划采用其他的单列索引

trace内容


由于order by的原因,执行计划使用的索引又变了....究竟这么变是好是坏?(有生之年系列+1,今天实在是写不动了)

写在最后:遇上order by+limit的时候,要么就用联合索引把where条件和order by的列全部包进去,要么就不要在order by的那一列上面建立单独的索引

PS:从字面上看,merge_index的特性也许会有奇效也说不定......(有生之年系列+1,天天在挖坑来坑自己.........~( ̄ε(# ̄)╰╮o( ̄皿 ̄///))

时间: 2024-10-03 06:28:24

MySQL之SQL分析三部曲实际案例(三)--limit的陷阱的相关文章

MySQL之SQL分析三部曲实际案例(二)

附上MySQL之SQL分析三部曲地址http://blog.itpub.net/29510932/viewspace-1709732/ -------------------------------------------------------------------------------------------------正文-----------------------------------------------------------------------------------

MySQL之SQL分析三部曲实际案例(一)

附上MySQL之SQL分析三部曲地址http://blog.itpub.net/29510932/viewspace-1709732/ -------------------------------------------------------------------------------------------------正文-----------------------------------------------------------------------------------

MySQL之SQL分析三部曲实际案例(六)--file sort与key_len

-------------------------------------------------------------------------------------------------正文--------------------------------------------------------------------------------------------------------------- 问题发生于对即将上线的SQL进行review时,实际问题的截图隐去部分生产环境

MySQL之SQL分析三部曲实际案例(五)--临时表,优化器的选择

-------------------------------------------------------------------------------------------------正文---------------------------------------------------------------------------------------------------------------问题出现于生产环境,为了方便表述,在测试环境构造了类似的场景 所有操作都是基于M

MySQL之SQL分析三部曲

在倒腾DB的时候,SQL会占据非常大的一部分时间,遇到执行效率不高的SQL时,就需要想办法找到执行效率不高的原因,这里简单记录分析SQL的三个步骤~ 使用的数据库版本为MySQL-5.7.7-rc -----------------------------------------------------------------------------------------正文------------------------------------------------------------

MySQL SQL 分析 - 参数化查询 vs query cache 功能

query cache,  mysql 5 开始附带的一个功能, 与引擎无关, 只与数据查询语法相关.   测试描述: 当前使用中是 MySQL-5.6.14 Linux RHEL6  64 位系统产生环境,  使用 INNODB 引擎, 分配 innodb 2g 内存空间   [root@TiYanPlat ~]# uname -a Linux TiYanPlat 2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64

mysql监控、性能调优及三范式理解

原文:mysql监控.性能调优及三范式理解 1监控          工具:sp on mysql     sp系列可监控各种数据库   2调优 2.1 DB层操作与调优               2.1.1.开启慢查询                             在My.cnf文件中添加如下内容(如果不知道my.cnf的路径可使用find / -name my.cnf进行查找):                             在mysqld下添加            

mysql 显示SQL语句执行时间的代码_Mysql

MySQL 的 SQL 語法調整主要都是使用 EXPLAIN , 但是這個並沒辦法知道詳細的 Ram(Memory)/CPU 等使用量. 於 MySQL 5.0.37 以上開始支援 MySQL Query Profiler, 可以查詢到此 SQL 會執行多少時間, 並看出 CPU/Memory 使用量, 執行過程中 System lock, Table lock 花多少時間等等. MySQL Query Profile 詳細介紹可見: Using the New MySQL Query Prof

PHP+MYSQL网站SQL Injection攻防

程序员们写代码的时候讲究TDD(测试驱动开发):在实现一个功能前,会先写一个测试用例,然后再编写代码使之运行通过.其实当黑客SQL Injection时,同样是一个TDD的过程:他们会先尝试着让程序报错,然后一点一点的修正参数内容,当程序再次运行成功之时,注入也就随之成功了. 进攻: 假设你的程序里有类似下面内容的脚本: $sql = "SELECT id, title, content FROM articles WHERE id = {$_GET['id']}"; 正常访问时其UR