• 深分页优化总结


    前言

    最近有面试过也遇到了问关于深分页问题,在这里简单从MySQL、ES等方面分享一下自己对该问题认识和总结。


    一、深分页定义

    可以从ES定义上来划分浅分页和深分页的边界,即页数超过10000页为深分页,少于10000页为浅分页。

    二、MySQL深分页

    关于MySQL深分页问题先看一下以下这条SQL语句:

    SELECT	* FROM	t_order WHERE user_id = 1001 LIMIT 1000000, 10 
    --------------------------------------------------------------
    查询时间:89.15s
    
    • 1
    • 2
    • 3

    如果t_order表数据超过1000w直接执行以上SQL会非常慢,这就是典型深分页问题。
    简单说一下关于在MySQL上limit执行过程:是会先扫描offset+n行,然后再丢弃掉前offset行,返回后n行数据。
    从这里就可以看出来以上SQL之所有会慢主要问题是因为做了大量(offset+n行)的回表操作,则关于MySQL深分页问题主要是大量回表问。

    1.最大ID

    select * from table_name where id > 最大id limit 10000, 10
    
    • 1

    具体实现是:每一次查询把本批数据的最大ID传给前端,查询下一页的时候再带到后台。
    这种方式有一个很大的局限性问题就是它只适用于主键ID自增的情况,分布式ID(雪花算法等)则不行,还需要考虑连续型字段datetime,sequence 等。

    该方案可以极大优化MySQL深分页问题,能优化到ms级别。

    2.延迟关联

    刚刚有提到MySQL深分页问题主要是回表问题,那么解决回表问题肯定得用到索引覆盖技术,在《高性能MySQL》书上叫这种解决深分页问题的方法叫做延迟关联。
    具体解决方案的可以看一下我的这篇博文:延迟关联

    SELECT	* FROM	t_order t
    RIGHT JOIN (
    	SELECT id
    	FROM t_order
    	WHERE user_id = 1001
    	LIMIT 1000000,50
    ) tmp ON tmp.id = t.id
    --------------------------------------------------------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该方案解决了id不需要自增的问题,但是优化性能较低,在数据量大的情况下只能优化到秒级别的。

    三、ES深分页

    1.浅分页

    ES浅分页(From,Size)过程:ES是基于数据分片的,假设有3个分片,from=100,size=10。则会根据排序规则从3个分片中各取回100条数据数据,然后汇总成300条数据后选择最后面的10条数据。
    且From最大默认值是10000,如果超过这个值就会报错,虽然这个最大值可以修改,但是不推荐,因为会极大的影响查询效率。

    2.scroll深分页

    为了满足深度分页的场景,ES 提供了 scroll 的方式进行分页读取。
    原理上是对某次查询生成一个游标 scroll_id , 后续的查询只需要根据这个游标去取数据,直到结果集中返回的 hits 字段为空,就表示遍历结束。scroll_id 的生成可以理解为建立了一个临时的历史快照,在此之后的增删改查等操作不会影响到这个快照的结果。
    scroll方式官方的建议并不是用于实时的请求,因为每一个 scroll_id 不仅会占用大量的资源(特别是排序的请求),而且是生成的历史快照,对于数据的变更不会反映到快照上。这种方式往往用于非实时处理大量数据的情况,比如要进行数据迁移或者索引变更之类的

    3.search_after深分页

    ES5之后提供search_after,它是假分页方式,基本原理是根据上一页的最后一条,确定下一页的位置。
    可以支持实时检索,而且性能也比scroll好,但是它只能一直下一页。

    通过以上对比可以看出来ES的深分页方案也并没解决常见的需求问题。


    四、常见深分页案例

    一般数据量级别没有达到时根本就不存在什么深分页问题,那么我们可以看一下淘宝和京东他们是怎么解决深分页问题:
    在这里插入图片描述
    在这里插入图片描述
    固定分页:
    无论有多少页数据都对检索后数据只取前100页。

    滚动分页:
    只支持上一页或下一页操作。

  • 相关阅读:
    【云原生之K8s】 Kubernetes核心组件
    后端的datetime类型数据转为string作为(vue)前端的时间YYYY-MM-DD HH:mm:ss
    SpringSecurity_权限管理
    企业为什么要做等保?不做等保有什么后果?
    Win:在 Windows Server 中的 NIC Teaming
    设计模式学习(十一):组合模式
    H5链接分享到微信中形成小卡片(后端代码签名实现(超详细))
    SpringSecurity入门
    WebKit Inside: CSS 样式表解码字符集
    Nginx学习(3)—— Nginx的应用
  • 原文地址:https://blog.csdn.net/qq_32979219/article/details/126222572