线上有这样一个Sql耗时很长,统计 了下基本在80~200s之间。
?
SQL: SELECT `mysites_vultask`.`id`, `mysites_vultask`.`site_id`, `mysites_vultask`.`status`, `mysites_vultask`.`timestamp`, `mysites_vultask`.`conf`, `mysites_vultask`.`task_state`, `mysites_vultask`.`task_id`, `mysites_vultask`.`error_id`, `mysites_vultask`.`endtime`, `mysites_vultask`.`messages`, `mysites_vultask`.`operation`, `mysites_vultask`.`report_name`, `mysites_vultask`.`work_id`, `mysites_vultask`.`reload`, `mysites_vultask`.`urllist`, `mysites_vultask`.`task_type`, `mysites_vultask`.`task_serial`, `mysites_vultask`.`task_option`, `mysites_vultask`.`strategy`, `mysites_vultask`.`check_status`, `mysites_vultask`.`score` FROM `mysites_vultask` WHERE (`mysites_vultask`.`status` = 'Y'? AND `mysites_vultask`.`site_id` = 2761? AND `mysites_vultask`.`report_name` IS NOT NULL AND NOT ((`mysites_vultask`.`report_name` = ''? AND `mysites_vultask`.`report_name` IS NOT NULL))) ORDER BY `mysites_vultask`.`endtime` DESC;
?
一、查看其执行过程,在creating sort index 占用了绝大部分的时间,如图1,通过google和度娘:creating sort index 代表了mysql 要通过内部临时表的方案来处理这次Select,当然这个表是内存中的。当内存放不下时,全部copy到磁盘。导致性能极具下降。另外:
MySQL 临时表分为“内存临时表”和“磁盘临时表”,其中内存临时表使用MySQL的MEMORY存储引擎,磁盘临时表使用MySQL的 MyISAM存储引擎;
一般情况下,MySQL会先创建内存 临时表,但内存临时表超过配置指定的值后,MySQL会将内存临时表导出到磁盘临时表; 详细见参考资料1.
????????????????? ![]()

?

?
二、由于使用order by 一定场景下会带来creating sort index,故先去掉后,继续查看执行情况,如下图,发现查询时间还在100秒以上,这次时间主要在Sending data上边。
?? Sending data :线程在读取和处理SELECT语句,发送数据到客户端。由于语句需要大量的磁盘访问,这个状态会在语句的整个生命周期中占据最长的一个状态。
?
EXPLAIN 会发现,这条sql语句会利用表中已建立好的索引,理论上不应该慢啊。但是要注意,我们SELECT的是表中所有的字段。所以MySQL要根据索引去定位出具体的数据行返回给客户端。
?
SQL: SELECT `mysites_vultask`.`id`, `mysites_vultask`.`site_id`, `mysites_vultask`.`status`, `mysites_vultask`.`timestamp`, `mysites_vultask`.`conf`, `mysites_vultask`.`task_state`, `mysites_vultask`.`task_id`, `mysites_vultask`.`error_id`, `mysites_vultask`.`endtime`, `mysites_vultask`.`messages`, `mysites_vultask`.`operation`, `mysites_vultask`.`report_name`, `mysites_vultask`.`work_id`, `mysites_vultask`.`reload`, `mysites_vultask`.`urllist`, `mysites_vultask`.`task_type`, `mysites_vultask`.`task_serial`, `mysites_vultask`.`task_option`, `mysites_vultask`.`strategy`, `mysites_vultask`.`check_status`, `mysites_vultask`.`score` FROM `mysites_vultask` WHERE (`mysites_vultask`.`status` = 'Y'? AND `mysites_vultask`.`site_id` = 2761? AND `mysites_vultask`.`report_name` IS NOT NULL AND NOT ((`mysites_vultask`.`report_name` = ''? AND `mysites_vultask`.`report_name` IS NOT NULL)));
?
?

?
三、问题基本定位到了表中的列的情况,那就看看表的大概情况吧~
??? 执行:select?*?from?information_schema.tables?where?TABLE_NAME?like?'%mysites_vul%';
发现该表的平均行长度竟然有70K, 查看该表结构和数据。发现messages 和 urllist 字段存储了改任务的扫描结果,有的达到了几十M。
innodb引擎中。对于大字段如text blob等,只会存放768个字节在数据页中,而剩余的数据会存储在溢出段中。而在我们的表中messages 和 urllist 太大。存放在了很多页上。
导致每次查询该字段都会去访问很多页(ps:根据网上同行测试。 innodb中溢出页中的数据也不会缓存)。

?
?
四:根据分析,把messages 和 urllist 从SELECT都去掉。在看效果。仅仅用了0.24s就查询 出来了。
SQL:
SELECT?`mysites_vultask`.`id`,?`mysites_vultask`.`site_id`,?`mysites_vultask`.`status`,?
`mysites_vultask`.`timestamp`,?`mysites_vultask`.`conf`,?`mysites_vultask`.`task_state`,?
`mysites_vultask`.`task_id`,?`mysites_vultask`.`error_id`,?`mysites_vultask`.`endtime`,
#?`mysites_vultask`.`messages`,
?`mysites_vultask`.`operation`,?`mysites_vultask`.`report_name`,?
`mysites_vultask`.`work_id`,?`mysites_vultask`.`reload`,?
#`mysites_vultask`.`urllist`,?
`mysites_vultask`.`task_type`,?`mysites_vultask`.`task_serial`,?`mysites_vultask`.`task_option`,
?`mysites_vultask`.`strategy`,?`mysites_vultask`.`check_status`,?
`mysites_vultask`.`score`?FROM?`mysites_vultask`?
WHERE?(`mysites_vultask`.`status`?=?'Y'??AND?`mysites_vultask`.`site_id`?=?2761
??AND?`mysites_vultask`.`report_name`?IS?NOT?NULL?AND?NOT?((`mysites_vultask`.`report_name`?=?''
??AND?`mysites_vultask`.`report_name`?IS?NOT?NULL)))?
ORDER?BY?`mysites_vultask`.`endtime`?DESC;
?
五、 总结一下:
(1)表设计时需要考虑到这样的问题。像这种存放大数据的字段需要拆分到其他 表中。或者是考虑细化存储其中的数据
(2)select时,用哪个就查哪个。不要select没用的列,或者 Select *
(3)只要固定几行数据就使用LIMIT
?
参考资料:????
(1)http://blog.csdn.net/chenchaoxing/article/details/25214397
?
(2)http://yoshinorimatsunobu.blogspot.com /2010/11/handling-long-textsblobs-in-innodb-1-to.html