- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
分表分页/跨库分页为什么这么难?
2021-08-21
更多内容关注:fullstack888
当业务数据达到肯定量级(比如:mysql单表记录量1千万)后,通常会考虑“分库分表”将数据分散到不同的库或表中,这样可以大大提高读/写功能。但是问题来了,对于 select * from table limit offset , pagesize?这种分页方式,原来一条语句就可以简约搞定的事情会变得很简单,本文将与大家一起探讨分库分表后分页面临的新问题。
?
一、分表对分页的影响
比如有一张表,里面有8条记录(为简约起见,假设该表上只要1个自增ID),数学上可以笼统成1个(有序)数列(注:为便利争辩,不加特殊说明的情况下,文本中数列的挨次,均指升序)
(1,2,3,4,5,6,7,8)
假如要取出上面红色标识的2,3这二条记录,limit 1,2 就行了。
现在假如分成2张表(即:原来的数列,拆分成2个非空子数列),一般来讲,有二种常用分法:
1.1 分段法(比如:有时间属性的数据,类似订单这种,可以按下单时间拆分,每个月1张表)
(1,2,3,4)
(5,6,7,8)
沿用之前的limit x,y的思路,每个分表上 limit 1,2,会得到如下2个子数列:
(2,3)
(6,7)
然后在内存中合并排序,再取前2条 (2,3,6,7) = (2,3) ,貌似看上去也符合预期(这个思路也称为归并),但这只是假象。当要取的分页数据落在不同的子数列上时,就能发觉问题:
(1,2,3,4,5,6,7,8) 比如,我们要从4个位置开头,连续取2个元素,即: limit 3,2
(1,2,3,4)?= limit 3,2?=(4)
(5,6,7,8)?= limit 3,2 =(8)
最终合并出来的结果是(4,8) 与正确结果 (4,5)相比,明显不对。
?
1.2 模余均摊法(比如:字段值对2取模求余数,依据余数打算分到哪个表,该方法也简称为取余法)
(1,3,5,7)
(2,4,6,8)
归并排序的思路在分段法上行不通,对于取模均摊同样也不行,仍以 limit 1,2为例,原始序列取出来的结果是(2,3),假如用归并的思路:
(1,3,5,7)= limit 1,2 =(3 ,5)
(2,4,6,8)= limit 1,2 =(4, 6)
内存合并排序后,取前2个,最终结果为(3 , 4)
结论:不管分库分表接受什么分法,简约归并的思路,都无法正确处理分页问题。
?
二、全局法(limit x+y)
反思一下刚才的归并思路,本质上我们在每个子数列(即:分表)上limit x,y 时,取出来的数据就有可能已经产生缺失了。网上有一篇广为流转的文章 业界难题-跨库分页”,作者在文中提出了一个方案:把范围扩大,分表sql上的limit x,y 变成 limit 0, x+y ,这样改写后,相当于分表中把每页最终一条数据之前的全部数据全都取出来了(当然:这里面可能会有不需要的多余数据),然后内存中合并在一起,再取x偏移量后的y条数据。
用前面的例子验证一下:
原序列:(1,2,3,4,5,6,7,8),需要取出limit 1,2 ,即:(2,3)
2.1 按分段法拆成2段:
(1 ,? 2 , 3 , 4)?= limit 1,2 =改写成 limit 0, 1+2?= (1,2,3)
(5 , 6 , 7 , 8)?= limit 1,2 =改写成 limit 0, 1+2?= (5,6,7)
将子数列合并排序= { 1,2,3,5,6,7}?= 按原始偏移量 limit 1,2 ={2,3}?正确
假如原数列中要取的数据,正好落在2个子数列上(1,2,3,4,5,6,7,8),需要取出limit 3,2 ,即:(4,5)
(1 ,? 2 , 3 , 4)?= limit 3,2 =改写成 limit 0, 3+2?= (1,2,3,4)?
(5 , 6 , 7 , 8)?= limit 3,2 =改写成 limit 0, 3+2?= (5,6,7,8)
将子数列合并排序= (1,2,3,4,5,6,7,8)?= 按原始偏移量 limit 3,2 = (4,5) 也符合预期。
?
2.2?取模均摊拆成2段
(1,3,5,7)?= limit 1,2 -改写成 limit 0, 1+2?= (1,3 ,5)
(2,4,6,8)?= limit 1,2?-改写成 limit 0, 1+2= (2,4,6)
将子序列合并= (1,2,3,4,5,6)?= 按原始偏移量 limit 1,2 =(2,3) 正确
该方法缺点也很明显:取出的记录太多了,比如 limit10 -?改写后变成 limit 0, 1000001
文档评论(0)