MySQL filesort优化案例一则
今天遇到一个filesort优化的案例,感觉不错,分享出来。
MySQL中filesort是什么意思?官方手册定义:
MySQL must do an extra pass to find out how to retrieve the rows in sorted order. The sort is done by going through all rows according to the join type and storing the sort key and pointer to the row for all rows that match the WHERE clause . The keys then are sorted and the rows are retrieved in sorted order。
一般来说如果有你的SQL查询语句中有order by且没有合适的索引时,通过EXPLAIN query可以在Extra列查看到Using filesort字样,当然一般来说此时也代表你需要去优化它了,无论是通过优化索引还是改变SQL查询实现方式。
先看表结构信息:
CREATE TABLE `tbxxxx` (
`id` int(10) unsigned NOT NULL auto_increment COMMENT '??id',
`a` varchar(20) default NULL COMMENT '??id',
`base62_id` varchar(10) default NULL COMMENT '??base62_id',
`userid` varchar(20) default NULL COMMENT '??id',
`category` int(5) unsigned default NULL COMMENT '????id',
`rate` decimal(10,2) NOT NULL default '0.00' COMMENT '??',
`status` enum('Y','N') NOT NULL default 'Y' COMMENT '??',
`releaseTime` datetime default NULL COMMENT '??????',
`createTime` datetime default NULL COMMENT '??????',
`content` text,
PRIMARY KEY (`id`),
UNIQUE KEY `a` (`a`),
KEY `releaseTime` (`releaseTime`),
KEY `rate` (`rate`),
KEY `crr` (`category`,`rate`,`releaseTime`),
KEY `idx_c_r_rate` (`category`,`releaseTime`,`rate`),
KEY `idx_status_rt_rate` (`status`,`releaseTime`,`rate`),
KEY `idx_status_rate_release` (`status`,`rate`,`releaseTime`)
) ENGINE=MyISAM AUTO_INCREMENT=3346255 DEFAULT CHARSET=utf8 COMMENT='?????'
1 row in set (0.15 sec)
ps:上面表结构中有些索引并不是线上实际存在的,这是做测试用临时添加的。
然后业务有如下查询:
SELECT a, content FROM tbxxxxx WHERE `status`='Y' and releaseTime > '2013-07-08 11:00:00' ORDER BY rate DESC LIMIT 0, 10
对于这类型的查询可能第一反应是建立一个(status, releaseTime, rate)的复合索引, 然后通过EXPLAIN发现优化器也是这么选择的:
explain SELECT a, content FROM tbxxxxx WHERE `status`='Y' and releaseTime > '2013-07-08 11:00:00' ORDER BY rate DESC LIMIT 0, 10; +----+-------------+-----------+------+--------------------------------------------------------+--------------------+---------+-------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+--------------------------------------------------------+--------------------+---------+-------+--------+-----------------------------+
| 1 | SIMPLE | tbxxxxx | ref | releaseTime,idx_status_rt_rate,idx_status_rate_release | idx_status_rt_rate | 1 | const | 531837 | Using where; Using filesort |
+----+-------------+-----------+------+--------------------------------------------------------+--------------------+---------+-------+--------+-----------------------------+
1 row in set (0.15 sec)
上面的key_len=1是能理解的,因为MySQL 5.6以前没有ICP,所releaseTime这种范围查询是无法利用索引。status占一个字节。但是从Extra中我们可以发现由于order by rate导致了filesort。那么这个索引该怎么调整才能避免filesort呢?其实在一刚开始没想到得一定去优化这个filesort的开销(后来证明这个案例中得filesort占了99%的开销),而是想着怎么去优化扫描的行数,使筛选的得到的行更少,这样可以减少回表带来的开销。但是通过打开profile之后,发现了问题最关键的地方:
上面的图标可以显示结果集排序占了绝大部分的时间开销。那么此时问题就变成了该怎么来优化掉这个可恶的filesort,于是添加了一个(status, rate, releaseTime)字段的索引,测试发现优化器依然默认会走(status, releaseTime, rate)这个复合索引, 于是只能通过用use index()的语法来强制走目标索引:
explain SELECT a, content FROM tbxxxxx use index(idx_status_rate_release) WHERE `status`='Y' and releaseTime > '2013-07-08 11:00:00' ORDER BY rate DESC LIMIT 0, 10;
+----+-------------+-----------+------+-------------------------+-------------------------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+-------------------------+-------------------------+---------+-------+---------+-------------+
| 1 | SIMPLE | tbxxxxxx | ref | idx_status_rate_release | idx_status_rate_release | 1 | const | 1057094 | Using where |
+----+-------------+-----------+------+-------------------------+-------------------------+---------+-------+---------+-------------+
1 row in set (0.00 sec)
从执行计划可以看出, 此时没有了filesort这个阶段,因为默认status, rate这个索引前缀就是按照rate来排序的,因此正好可以利用索引的数据有序来达到最终的order by rate效果。细心的朋友可能会发现在这个执行计划中估算扫描的行数是上一个执行计划的2倍, 多扫描这么多行开销不大吗(这也是为什么当初第一反应优化这条SQL时会考虑优化索引来减少扫描的行数)? 事实上证明这个开销相对于filesort来说已经很小,有两点可以证明:profile的分析显示99%的时间是耗在sorting result,第二,在线上一个从库上测试第二个执行计划查询时间为0.1s左右,而第一个执行计划的查询时间在3s左右。虽然说一般来说并不建议使用use index这种语法,后期的不确定性较大,但是既然提供这种语法就有它自己的理由, 用好了自然有优势,先这么将就着吧。另外这里需要说明的是:(status, rate, releaseTime)这个索引中只有rate是必须得, status由于只有两个取值,筛选效果很不明显, releaseTime用不到(ICP后可能能用到)
最后是两点小感悟:1.MySQL的优化器还是那么有点坑爹, 有时候不靠谱。2.有时候优化一个SQL还是不能完全凭直觉,平常的经验,profile这种命令可以完全将一个SQL查询执行过程中各个阶段的开销都统计出来,这样我们就有了针对一个SQL的优化关键点,这样才能做不到不盲目,从而高效快速的优化。
MySQL filesort优化案例一则的更多相关文章
- MySQL参数优化案例
环境介绍 优化层级与指导思想 优化过程 最小化安装情况下的性能表现 优化innodb_buffer_pool_size 优化innodb_log_files_in_group&innodb_l ...
- MySQL索引优化案例
这里我们分成三种情况进行分析,分别是单表,两表,三表 1.单表 CREATE TABLE IF NOT EXISTS `article`( `id` ) NOT NULL PRIMARY KEY AU ...
- MySQL索引优化案例浅析
MySQL是关系型数据库的一种,查询功能强,数据一致性高,数据安全性高,支持二级索引.但是性能比起非关系型数据库稍弱,特别是百万级以上的数据,很容易出现查询慢的现象.这时候要分析慢的原因,一般情况下是 ...
- mysql depended_query 优化案例一则
月度利息统计sql优化 原因:写的sql语句复杂,理解起来有难度,另一方面,查询性能比较低 原来的语句如下: SELECT tp.year, tp.month, tp.bid_id, b.`title ...
- MySQL的索引单表优化案例分析
建表 建立本次优化案例中所需的数据库及数据表 CREATE DATABASE db0206; USE db0206; CREATE TABLE `db0206`.`article`( `id` INT ...
- mysql优化案例
MySQL优化案例 Mysql5.1大表分区效率测试 Mysql5.1大表分区效率测试MySQL | add at 2009-03-27 12:29:31 by PConline | view:60, ...
- 记一次mysql多表查询(left jion)优化案例
一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...
- Mysql 排序优化与索引使用(转)
为了优化SQL语句的排序性能,最好的情况是避免排序,合理利用索引是一个不错的方法.因为索引本身也是有序的,如果在需要排序的字段上面建立了合适的索引,那么就可以跳过排序的过程,提高SQL的查询速度.下面 ...
- MySQL分页优化中的“INNER JOIN方式优化分页算法”到底在什么情况下会生效?
本文出处:http://www.cnblogs.com/wy123/p/7003157.html 最近无意间看到一个MySQL分页优化的测试案例,并没有非常具体地说明测试场景的情况下,给出了一种经典的 ...
随机推荐
- 【集训笔记】母函数【母函数模板】【HDOJ1028【HDOJ1085
以下资料摘自 http://www.cnblogs.com/wally/archive/2012/07/13/hdu1028_1085_1171_.html 生成函数是说,构造这么一个多项式函数g(x ...
- 基于visual Studio2013解决算法导论之054图的邻接矩阵表示
题目 图的邻接矩阵表示 解决代码及点评 // 图的邻接矩阵表示.cpp : 定义控制台应用程序的入口点. // #include <iostream> #include <l ...
- oracle scn浅析
1. 系统SCN号 查询系统SCN号的方法: select dbms_flashback.get_system_change_number from dual commit后系统SCN号会增长,但是即 ...
- B - 队列,推荐
Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Submit Status Desc ...
- SED修改指定行
一个文件:cat aa #如果第三行是5的话将改为8,很明显第三行是5所以 结果改变 [root@remote ~]# sed -e '3s/5/8/' aa [root@remote ~]# #如果 ...
- Linux下Nginx+tomcat应用系统性能优化
软件环境及服务器配置如下: Linux rh6.3,Tomcat7.0.29,Nginx1.2.7 mysql5.1,jdk1.6.0 mysql5.1 memcached 1.4.15 Xeno 2 ...
- Linux -FHS 标准
FHS (Filesystem Hierarchy Standard),其目的是让用户可以了解以安装软件通常放在那个文件下面. /bin 放置的是单用户维护模式下,能够被调用的命令.主要有cat,ch ...
- Qt学习之路(54): 自定义拖放数据对象
前面的例子都是使用的系统提供的拖放对象 QMimeData 进行拖放数据的存储,比如使用 QMimeData::setText() 创建文本,使用 QMimeData::urls() 创建 URL 对 ...
- The Apache™ Batik Project
Apache(tm) Batik SVG Toolkit - a Java-based toolkit for applications or applets that want to use ima ...
- c++怎样让返回对象的函数不调用拷贝构造函数
我们知道拷贝构造函数有两种“默默”的方式被调用 1. 想函数传入 值参数 2. 函数返回 值类型 今天我们讨论函数返回值类型的情况. 得到结论是 1. 当对象有拷贝构造函数(系统为我们生成.或者我们自 ...