水平分库分表后的分页查询

分库后,分页查询按照时间time来排序order by。

1.全局视野法

若查询第x页的数据,每页y条。一共n个库。
步骤:

  1. 将order by time offset (x*y+1) limit y,改写成order by time offset 0 limit (x*y+1) +y
  2. 服务层将改写后的SQL语句发往各个分库:即每库各取x页的数据
  3. 服务层将得到 n*(x*y+1+y) 条数据
  4. 服务层对得到的数据进行内存排序,内存排序后再取偏移量x*y+1后的y条记录,就是全局视野所需的一页数据

2.业务折衷法

2.1.禁止跳页查询

只提供“下一页”的功能

  1. 查询第1页数据
    每个库执行order by time where time>0 limit y
    得到 n*y条数据,内存排序,得到前y条,即为第1页。
    $time_max=第1页最大的time
  2. 获取第2页数据
    每个库依次查询
    order by time where time>$time_max limit y
    一共得到n*y条数据,取time最小的y条为第2页数据。
    $time_max=第2页最大的time

数据的传输量和排序的数据量不会随着不断翻页而导致性能下降。

3. 二次查询法

为了方便举例,假设2个库,一页5条数据,查询第200页的SQL语句为select * from T order by time offset 1000 limit 5;

  1. 查询改写
    改写为select * from T order by time offset 500 limit 5,并投递给所有的分库,注意,这个offset的500,来自于全局offset的总偏移量1000,除以水平切分数据库个数2
    如果是3个分库,则可以改写为select * from T order by time offset 333 limit 5
    假设这三个分库返回的数据(time, uid)如下:
    水平分库分表后的分页查询_第1张图片
    每个分库都返回的按照time排序的一页数据。

  2. 找到所返回3页全部数据的最小值
    水平分库分表后的分页查询_第2张图片
    第一个库,5条数据的time最小值是1487501123
    第二个库,5条数据的time最小值是1487501133
    第三个库,5条数据的time最小值是1487501143
    故,三页数据中,time最小值来自第一个库,time_min=1487501123,这个过程只需要比较各个分库第一条数据。

  3. 查询二次改写
    第二次要改写成一个between语句,between的起点是time_min,between的终点是原来每个分库各自返回数据的最大值:
    第一个分库,第一次返回数据的最大值是1487501523
    所以查询改写为select * from T order by time where time between time_min and 1487501523
    第二个分库,第一次返回数据的最大值是1487501323
    所以查询改写为select\ * from T order by time where time between time_min and 1487501323
    第三个分库,第一次返回数据的最大值是1487501553
    所以查询改写为select * from T order by time where time between time_min and 1487501553
    第二次查询会返回比第一次查询结果集更多的数据,假设这三个分库返回的数据(time, uid)如下:
    水平分库分表后的分页查询_第3张图片

  4. 在每个结果集中虚拟一个time_min记录,找到time_min在全局的offset
    水平分库分表后的分页查询_第4张图片
    故:
    time_min在第一个库的offset是333;
    time_min在第二个库的offset是331;
    time_min在第三个库的offset是330;
    综上,time_min在全局的offset是333+331+330=994;

  5. 得到time_min在全局的offset,就相当于有了全局视野,根据第二次的结果集,就能够得到全局offset 1000 limit 5的记录
    水平分库分表后的分页查询_第5张图片
    第二次查询在各个分库返回的结果集是有序的,又知道了time_min在全局的offset是994,一路排下来,容易知道全局offset 1000 limit 5的一页记录(上图中黄色记录)。

你可能感兴趣的:(后端,#,面试突击)