加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

炸!业界难题,跨库分页的几种常见方案

发布时间:2019-05-15 04:58:59 所属栏目:建站 来源:58沈剑
导读:为什么需要研究跨库分页? 互联网很多业务都有分页拉取数据的需求,例如: 微信消息过多时,拉取第N页消息; 京东下单过多时,拉取第N页订单; 浏览58同城,查看第N页帖子; 这些业务场景对应的消息表,订单表,帖子表分页拉取需求,都有这样一些共同的特点:

为了方便举例,假设一页只有5条数据,查询第200页的SQL语句为:

  1. select * from T order by time offset 1000 limit 5; 

步骤一:查询改写

  1. 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个分库,则可以改写为

  1. select * from T order by time offset 333 limit 5; 

假设这三个分库返回的数据(time, uid)如下:

炸!业界难题,跨库分页的几种常见方案

可以看到,每个分库都是返回的按照time排序的一页数据。

步骤二:找到所返回3页全部数据的最小值

  • 第一个库,5条数据的time最小值是1487501123;
  • 第二个库,5条数据的time最小值是1487501133;
  • 第三个库,5条数据的time最小值是1487501143;

炸!业界难题,跨库分页的几种常见方案

故,三页数据中,time最小值来自第一个库,time_min=1487501123,这个过程只需要比较各个分库第一条数据,时间复杂度很低。

画外音:这个time_min非常重要,后文每一个步骤要都要用到time_min。

步骤三:查询二次改写

第一次改写的SQL语句是

  1. elect * from T order by time offset 333 limit 5; 

第二次要改写成一个between语句:

  • between的起点是time_min
  • between的终点是原来每个分库各自返回数据的最大值

第一个分库,第一次返回数据的最大值是1487501523

所以查询改写为:

  1. select * from T order by time where time between time_min and 1487501523; 

第二个分库,第一次返回数据的最大值是1487501323

所以查询改写为

  1. select * from T order by time where time between time_min and 1487501323; 

第三个分库,第一次返回数据的最大值是1487501553

所以查询改写为

  1. select * from T order by time where time between time_min and 1487501553; 

相对第一次查询,第二次查询条件放宽了,故第二次查询会返回比第一次查询结果集更多的数据,假设这三个分库返回的数据(time, uid)如下:

炸!业界难题,跨库分页的几种常见方案

可以看到:

  • 分库一的结果集,由于time_min来自原来的分库一,所以分库一的返回结果集和第一次查询相同(所以其实这次访问是可以省略的);
  • 分库二的结果集,比第一次多返回了1条数据,头部的1条记录(time最小的记录)是新的(上图中粉色记录);
  • 分库三的结果集,比第一次多返回了2条数据,头部的2条记录(time最小的2条记录)是新的(上图中粉色记录);

步骤四:在每个结果集中虚拟一个time_min记录,找到time_min在全局的offset

炸!业界难题,跨库分页的几种常见方案

在第一个库中,time_min在第一个库的offset是333;

在第二个库中,(1487501133, uid_aa)的offset是333(根据第一次查询条件得出的),故虚拟time_min在第二个库的offset是331;

画外音:从333往前推演。

在第三个库中,(1487501143, uid_aaa)的offset是333(根据第一次查询条件得出的),故虚拟time_min在第三个库的offset是330;

画外音:从333往前推演。

综上,time_min在全局的offset是333+331+330=994。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读