mysql5.6 分页查询优化html
场景:mysql
表结构:主键(非自增)contentCode(varchar),过滤条件列为updateTime(timeStamp),已经为timestamp创建索引。sql
搜索sql为:函数
SELECT * FROM my_hello_table WHERE updateTime >= '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000
问题:数据在分页到60w后,分页查询时间为5.8s左右。没法忍受。测试
缘由:虽然走了索引,但mysq5.6 对于分页的操做是先根据过滤条件去索引查询出全部的updateTime,而后根据updateTime依次查询出60w数据,而后抛弃前59w9k条查询出数据,而后获取最后的1k条。优化
分页的这种越到后面用时越长的问题,是mysql5的一个失误,在mysql8以后的版本貌似获得了解决。code
优化:整体思路是走索引,走索引,仍是走索引。htm
首先咱们经过分页条件查询,只走updateTime索引,而后获取全部的主键,此时mysql是不回主表的。而后经过in 查询主表中全部在此范围的数据。blog
参考http://www.javashuo.com/article/p-qefdncmw-dz.html排序
有以下sql:
SELECT * FROM my_hello_table WHERE contentCode IN ( SELECT contentCode FROM my_hello_table WHERE updateTime > '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000 ) );
可是,惋惜的是,会有以下问题:
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
解决方法有 伪表进行表链接操做 和 in里面使用limit 参考:
https://www.cnblogs.com/c-h-y/p/9946813.html
最后 的sql为:
in 里面 用limit 的sql:
SELECT * FROM my_hello_table WHERE contentCode IN ( SELECT t.contentCode FROM ( SELECT contentCode FROM my_hello_table WHERE updateTime > '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000 ) AS t );
伪表 表链接
SELECT a.* FROM my_hello_table a INNER JOIN ( SELECT contentCode FROM my_hello_table WHERE updateTime > '2019-04-21 14:37:38' AND updateTime <= '2019-04-27 16:36:57' LIMIT 599000, 1000 ) AS b ON a.contentCode = b.contentCode
两种方式推荐第二种。避免了in语句。进行explain诊断会发现第二种效率高不少。
最后通过测试,查询时间由原来的5.8秒 优化到1.2s左右,优化率搞到400%。
记录下sql语句的完整执行顺序
一、from子句组装来自不一样数据源的数据;
二、where子句基于指定的条件对记录行进行筛选;
三、group by子句将数据划分为多个分组;
四、使用汇集函数进行计算;
五、使用having子句筛选分组;
六、计算全部的表达式;
七、使用order by对结果集进行排序。