• 场景之分页查询设计


    一、场景

    后端开发中,无论是管理后台还是面向普通用户,必不可少的涉及到批量数据的查询,这种查询的结果通产在前端以列表分页的形式展示出来,包含的参数包括,页码pageNum,每页记录数pageSize或者说是页面大小,总共多少条记录total等。

    其中前端传入参数的时候可能还包含,日期范围startTime,endTime,以及涉及到根据商品名的模糊匹配等,还有包括按照筛选字段正序倒序排序等。

    二、实现

    由于筛选条件通常是多种多样的,并且有些数据更新频繁,很难指定有效的缓存策略,即使有命中率以及使用率也很低,所以放弃缓存策略,压力直接给到了数据库这边。

    1、后台sql

    操作映射到后台,可能就是查询语句比如

    select * from table_name where create_time >= startTime and create_tiem <= endTime and product_name like %product% order by id desc limit pageNum offset pageSize *  (pageNum - 1)
    

    这里默认前端传参pageNum页数是0,所以在参数校验的时候,可以对页码重置,保证偏移量的正确。

    if request.PageNum == 0:
        pageNum = 1
    

    根据页码和页面大小可以计算出正确的偏移量

    offset = pageSize * (pageNum - 1)
    

    2、limit和offset

    执行sql的时候可以用offset,limit或者单独limit做分页。
    比如

    1. select* from table LIMIT 1,3
    2.select * from table LIMIT 3 OFFSET 1
    

    上面两种写法都表示取2,3,4三条条数据。

    • 1中,limit后边跟两个参数,第一个数表示要跳过的数量,后一位表示要取的数量。 LIMIT 1,3 就是跳过1条数据,从第2条数据开始取,取3条数据,也就是取2,3,4三条数据
    • 2中,limit和offset组合使用的时候,limit后面只能有一个参数,表示要取的的数量,offset表示要跳过的数量。LIMIT 3 OFFSET 1 表示跳过1条数据,从第2条数据开始取,取3条数据,也就是取2,3,4三条数据。

    3、问题

    以上采用limit和offset组合的方式区分偏移量和页面大小。
    实例中只是简单的多参数查询,如果涉及到的表记录数很多,需要逐行遍历,特别是在用户端显示的时候,如果用户从第一页直接请求最后一页,先忽略查询条件,假设每页20条,到后端的表现可能就是

    select * from table_name order by product_id offset 1000000 limit 20
    

    采用这种SQL查询分页的话,从100万数据中取出这20行数据的代价是非常大的,需要先查出前1000020条记录,根据product_id排序,然后抛弃前面1000000条。效率很低。

    三、优化

    所以想到对于数据库的只是查询操作,对表建立索引进行优化。

    1、覆盖索引

    如果对于sql查询的时候只要查找表中的部分字段,可以通过索引可以直接获取查询的结果,不再需要回表查询,也就是建立覆盖索引。

    select product_id, product_name from table order by product_id offset 1000000 limit 20
    

    对product_id 和product_name两个字段建立联合索引,查找的时候直接命中不会再去主键索引树找真实的记录。

    2、子查询优化

    因为实际开发中,只展示查询一两列字段操作是非常少的,因此上述的覆盖索引的适用范围就比较有限。
    而子查询避免了大量查询偏移量中的记录,而是只查询目标记录的Id,进而再去查询所有字段。

    select * from table where id>=(select id from table order by proudct_id limit 1000000, 1) limit 20;
    

    这种子查询也有自己的限制,

    • 要求主键ID必须是连续的,但是一般的业务中,可以定义默认主键或者自定义字自增主键,在删除的时候,采用逻辑删除(is_del=1)而非物理删除,对于新增的记录的可以实现主键连续。
    • where子句不允许再添加其他条件,但是可以在前端入参的时候做校验,对于默认参数的分页查询可以使用子查询优化。

    3、记录查询位置

    用户可能触发相同查询条件的多次分页查询,比如第一次

    select * from table where product_id > 2222 offset 500000 limit 10;
    

    经过此次查询之后后端记录下来商品id>2222的第500000条记录的id,如果在有类似查询如下

    select * from table where product_id > 2222 offset 1000000 limit 10;
    

    分页时直接从记录的这个500000条记录的id的位置开始扫描,从而避免MySQL扫描大量的数据再抛弃的操作。

  • 相关阅读:
    华为开源自研AI框架昇思MindSpore CPU-Ubuntu版本 Pip自动安装教程
    边缘计算网关在智能工业园区中的的应用及其优势-天拓四方
    网站更换域名、改版对网站有哪些影响,如何补救?
    【Vue2.0源码学习】生命周期篇-销毁阶段(destroy)
    5G专网技术实现与演进分析
    SuperMap iDesktop 处理带带号坐标系的数据
    springboot一次性定时任务插入1000万条数据
    ZooKeeper基础命令和Java客户端操作
    2.5 C++面向对象编程_类型转换
    大脑神经网络记忆原理图,记忆力机制的神经网络
  • 原文地址:https://www.cnblogs.com/welan/p/16519369.html