zoukankan      html  css  js  c++  java
  • Mysql数据库百万级记录查询分页优化

    很多的朋友在面试中会遇到这样的问题,也有很多的项目在运营一段时间后也会遇到MYSQL查询中变慢的一些瓶颈,今天这儿简单的介绍下我常用的几种查询分页的方法,我所知道的也无非就是索引、分表、子查询偏移,所以要是有什么不对或有更好的方法,欢迎大家留言讨论。
    
    效率分析关键词:explain + SQL语句
    
    一,最常见MYSQL最基本的分页方式limit:
    
        select * from `table` order by id desc limit 0, 20
    
    在中小数据量的情况下,这样的SQL足够用了,唯一需要注意的问题就是确保使用了索引。随着数据量的增加,页数会越来越多,在数据慢慢增长的过程中,可能就会出现limit 10000,20这样的情况,limit 10000,20的意思扫描满足条件的10020行,扔掉前面的10000行,返回最后的20行,问题就在这里,如果是limit 100000,100,需要扫描100100行,在一个高并发的应用里,每次查询需要扫描超过10W行,性能肯定大打折扣。
    
    这种方式有几个不足:较大的偏移(OFFSET)会增加结果集,小比例的低效分页足够产生磁盘I/O瓶颈,需要扫描的行多。
    
    简单的解决方法:不显示记录总数,没用户在乎这个数字;不让用户访问页数比较大的记录,重定向他们;避免count(*) ,不显示总数,让用户通过“下一页”来翻页 ,缓存总数;单独统计总数,在插入和删除时递增/递减
    
    二,第二种就是分表,计算HASH值,这儿不做介绍了,我目前也没有在项目中真正使用过这种方法,还停留在理论层次;
    
    三,第三种是偏移:
    
        SELECT * FROM `table` WHERE id <= (SELECT id FROM `table` ORDER BY id desc LIMIT ".($page-1)*$pagesize.", 1) ORDER BY id desc LIMIT $pagesize
    
    或者
    
        select * FROM `table` AS t1 JOIN (SELECT id FROM `table` ORDER BY id desc LIMIT 900,1) AS t2 WHERE t1.id<=t2.id order by t1.id desc limit 5
    
    原理就是记录住当前页id的最大值和最小值,计算跳转页面和当前页相对偏移,由于页面相近,这个偏移量不会很大,这样的话m值相对较小,大大减少扫 描的行数。其实传统的limit m,n,相对的偏移一直是第一页,这样的话越翻到后面,效率越差,而上面给出的方法就没有这样的问题。
    
    比如还是SELECT * FROM `table` ORDER BY id DESC,按id降序分页,每页20条,当前是第10页,当前页条目id最大的是9527,最小的是9500,如果我们只提供”上一页”、”下一页”这样 的跳转(不提供到第N页的跳转),那么在处理”上一页”的时候SQL语句可以是:
    
        SELECT * FROM `table` WHERE id > 9527 ORDER BY id ASC LIMIT 20;
    
    处理”下一页”的时候SQL语句可以是:
    
        SELECT * FROM `table` WHERE id < 9500 ORDER BY id DESC LIMIT 20;
    
    不管翻多少页,每次查询只扫描20行。
    
    缺点是只能提供”上一页”、”下一页”的链接形式,但是我一般来说非常喜欢”<上一页 1 2 3 4 5 6 7 8 9 下一页>”这样的链接方式,怎么办呢?
    
    如果LIMIT m,n不可避免的话,要优化效率,只有尽可能的让m小一下,我们扩展前面做法,还是SELECT * FROM `table` ORDER BY id DESC,按id降序分页,每页20条,当前是第10页,当前页条目id最大的是9527,最小的是9500,比如要跳到第8页,我看的SQL语句可以这 样写:
    
        SELECT * FROM `table` WHERE id > 9527 ORDER BY id ASC LIMIT 20,20;
    
    跳转到第13页:
    
        SELECT * FROM `table` WHERE id < 9500 ORDER BY id DESC LIMIT 40,20;
    
    注意SQL语句里面的ASC和DESC,如果是ASC取出来的结果,显示的时候记得倒置一下。
    
     
    
    整体来说在面对百万级数据的时候如果使用上面第三种方法来优化,系统性能上是能够得到很好的提升,在遇到复杂的查询时也尽量简化,减少运算量。 同时也尽量多的使用内存缓存,有条件的可以考虑分表、分库、阵列之类的大型解决方案了。
    
  • 相关阅读:
    【DOM】如何给div的placeholder传参
    【nvm】使用nvm将node升级到指定版本
    【Worktile】升级业务组件库后,http的数据返回整个response而不是data问题及解决方案
    js获取上传文件内容
    【正则】正则表达式-零宽断言(?=,?<=,?!,?<!)及常见报错
    【Angular】动态组件
    【扩展】div获取焦点或可编辑
    【CSS】position新增属性sticky
    thinkphp写接口返回固定的形式方法
    thinkphp5计算文件大小
  • 原文地址:https://www.cnblogs.com/flying-tx/p/4350688.html
Copyright © 2011-2022 走看看