设为首页 收藏本站
查看: 808|回复: 0

[经验分享] [MySQL性能优化系列]LIMIT语句优化

[复制链接]

尚未签到

发表于 2017-12-13 06:36:11 | 显示全部楼层 |阅读模式
1. 背景
  假设有如下SQL语句:
  

SELECT * FROM table1 LIMIT offset, rows  

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


  • 从“table”表中读取offset+rows行记录
  • 抛弃前面的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
  
……
  

  

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


  • 创建临时表
  

CREATE TEMPORARY TABLE tmp_timerec(  `uid` bigint(20) NOT NULL AUTO_INCREMENT,
  `timerec` datetime NOT NULL,
  PRIMARY KEY (`uid`))
  


  • 插入查询结果到临时表
  

INSERT INTO tmp_timerec  
SELECT null,timerec FROM message
  
WHERE evttype = 1 AND nodename = ‘node1’
  


  • 分多次查询临时表
  

SELECT timerec FROM tmp_timerec where uid > 0 LIMIT 1000  
……
  
SELECT timerec FROM tmp_timerec where uid > 999000 LIMIT 1000
  

  最后,附上MySQL性能优化系列的全部链接:


  • [MySQL性能优化系列]巧用索引 http://www.cnblogs.com/beynol/p/mysql-optimization-index.html
  • [MySQL性能优化系列]LIMIT语句优化 http://www.cnblogs.com/beynol/p/mysql-optimization-limit.html
  • [MySQL性能优化系列]提高缓存命中率 http://www.cnblogs.com/beynol/p/mysql-optimization-cache.html

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-423524-1-1.html 上篇帖子: PHP+MYSQL分页实现 下篇帖子: mysql io过高
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表