[MySQL性能优化系列]LIMIT语句优化

1. 背景

假设有如下SQL语句:

SELECT * FROM table1 LIMIT offset, rows

这是一条典型的LIMIT语句,常见的使用场景是,某些查询返回的内容特别多,而客户端处理能力有限,希望每次只取一部分结果进行处理。

上述SQL语句的实现机制是:

  1. 从“table”表中读取offset+rows行记录
  2. 抛弃前面的offset行记录,返回后面的rows行记录作为最终结果。

这种实现机制存在一个弊端:虽然只需要返回rows行记录,但却必须先访问offset行不会用到的记录。对一张数据量很大的表进行查询时,offset值可能非常大,此时limit语句的效率就非常低了。

2. 简单查询的LIMIT优化

假设表message表中有10万行记录,每次取1000条。
优化前:

SELECT message.* FROM message LIMIT 0,1000
SELECT message.* FROM message LIMIT 1000,1000
SELECT message.* FROM message LIMIT 2000,1000
……
SELECT message.* FROM message LIMIT 998000,1000
SELECT message.* FROM message LIMIT 999000,1000

优化后(利用自增主键,避免offset的使用):

SELECT message.* FROM message WHERE uid>0 LIMIT 1000
SELECT message.* FROM message WHERE uid>1000 LIMIT 1000
SELECT message.* FROM message WHERE uid>2000 LIMIT 1000
……
SELECT message.* FROM message WHERE uid>998000 LIMIT 1000
SELECT message.* FROM message WHERE uid>999000 LIMIT 1000

在笔者的机器上,优化前,SQL语句从前往后越来越慢(最后一条语句执行了150毫秒),而优化后,每条语句的耗时都是微妙级的。

3. 复杂查询的LIMIT优化

实际工程中遇到的查询,通常要复杂些,比如,多表查询、条件查询。这种情况下,查询结果通常不是按照自增主键的顺序逐一排列的。

例如,对于下述SQL语句,就不能像第二节那样优化了:

SELECT timerec FROM message WHERE evttype = 1 AND nodename = 'node1'
LIMIT 0,1000
……
SELECT timerec FROM message WHERE evttype = 1 AND nodename = 'node1'
LIMIT 999000,1000
……

优化方案:建立临时表(含自增主键)存储数十万行的查询结果,之后用第二节的方法分多次访问临时表、获取数据。

  1. 创建临时表
CREATE TEMPORARY TABLE tmp_timerec(
 `uid` bigint(20) NOT NULL AUTO_INCREMENT,
 `timerec` datetime NOT NULL,
 PRIMARY KEY (`uid`)) 
  1. 插入查询结果到临时表
INSERT INTO tmp_timerec
SELECT null,timerec FROM message
WHERE evttype = 1 AND nodename = ‘node1’
  1. 分多次查询临时表
SELECT timerec FROM tmp_timerec where uid > 0 LIMIT 1000
……
SELECT timerec FROM tmp_timerec where uid > 999000 LIMIT 1000


参考

  1. http://blog.csdn.net/fangwei1235/article/details/8621655
  2. http://stackoverflow.com/questions/1612957/mysql-index-configuration
  3. https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
  4. http://stackoverflow.com/questions/4481388/why-does-mysql-higher-limit-offset-slow-the-query-down
  5. order by是如何执行的,http://stackoverflow.com/questions/6954981/how-does-mysql-order-by-implemented-internally
  6. mysql 索引的原理,http://www.uml.org.cn/sjjm/201107145.asp
  7. MySQL存储引擎MyISAM与InnoDB的优劣, https://www.pureweber.com/article/myisam-vs-innodb/
  8. 存储引擎,http://coolshell.cn/articles/1846.html
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值