第一种:
也是最简单的一种:通过额外的添加一张关联表,属性中必有id属性,至于是否有库id属性和表id属性(既第几个库和第几个表)可有可无,因为这个可以根据id自行取模获取,注意这张表存放的数据是所有数据,但是胜在属性列少,只有提供索引的几个属性列,这样的话我们只需要select * from brand_temp where … limit 400,10(插叙第41页的数据,每页显示5条数据),然后我们获取了id之后就可以去对应的表中查询了
第二种:
最耗费性能的一种,如果我们要查询第一页的记录,单库单表的sql为:select * from db limit 0,10; 当我们分库分片之后 语句还是同样的语句,但是这时候我们需要对4个表返回的记录在内存中进行解析,然后通过id进行升序,取得前10条数据返回…数据量小,页码小的时候很ok,但是如果我们要查询第2页的数据的时候,sql单体架构的情况下为:select * from db limit 10,10; 但是在分布式数据库这样是不行的,数据很明显会丢失,弥补的方法是查询所有,sql语句为select * from db_x limit 0,10+10 //意味着需要查询的是本在单体架构上要查询的记录数加上之前的记录 ,然后再在内存中合并所有表返回的记录然后进行解析,最后取第10开始的记录 …可以看出这个方案一旦页码数达到n页,而每页显示的记录数为m条记录的时候,每个表需要查询的记录数为:(n-1)*m+m=nm条记录,内存中需要解析的记录数为 t * n * m 条记录,cpu不爆炸算我输
第三种:
采取的是基于业务的模式:迫使用户无法进行跳页查询,什么意思呢,就是用户只能点击下一页或者上一页的方式浏览,具体的做法在于查询得到记录数的同时记录下当前唯一id值的最大值,然后再次查询的时候添加where 条件…让我们从头开始捋: 第一次查询pageNum=1,pageSize=10 ,maxId=0->sql:select * from db_x where id>0 limit 10; 然后分发到对应的库的表中,将得到的4*10条数据合并,再在内存中进行解析排序,取前10条数据,同时将第10条数据的id=maxId单独取出渲染到前端页面上保存,这样当点击下一页的时候,这个maxId=10也提交上去了,sql 变成了select * from db_x where id>10 limit 10,然后继续解析,继续保存…这种方式返回的数据都是稳定的并且数据是连贯的(排序)
第四种:
传说中的最好的方式,支持跳页查询,这个方式核心在于2次sql查询,具体怎么做呢:
前提条件假设:查询第1001页的数据,每页显示10条记录
1):我们先记录下要查询的记录数的范围:(1001-1)*10=10000 开始,10010结束->10000-10010 单体的sql为:select * from db limit 10000,10; 我们总共有4个表,意味着:每个表的start应该为10000/4=2500,从而sql变成了: select * from db_x limit 2500,10; //假设是平均分配的,因而我们可以均分,不均分也没关系,后续操作会补齐 我们会得到4个表中的记录:(因为我demo还没写,所以先手写了) T1:(1,"a"),....... T2:(2,"b"),....... T3:(3,"c"),....... T4:(4,"d"),....... 真实数据第1001页不可能是1开头的,将就着看吧,过几天会一起讲rabbitMQ分布式一致性和这个demo一起发布的 ok,第一阶段的sql查询结束 2):对4个表中返回的记录进行id匹配(id如果非整型,自行用hashCode匹配),因为是升序查询,所以我们只需要比较下每个表的首条记录 的id值即可,获得了最小的minId=1,和各个表最大的那个值maxId;ok,转换sql思路,这里我们采用条件查询了(弥补操作第一步): select * from db_x where id between minId and maxId 这样我们就获取到了遗漏的数据(当然有多余的数据) 这样我们4个表中就返回了可能记录数各不相同的记录,第二步结束 3): 之后记录minId出现的位置,如T1出现的位置为2500,T2出现的位置为2500-2=2048 ,T3出现的位置为2500-3=2047 ,T4出现的位置 为2500-3=2047 则最终出现的记录数为:2500+2048+2047+2047=10000-2-3-3=9992,因此我们需要的查询的记录数需要从9992 依次往后取 8个开始,然后再取10个就是所求的数据,这种方式能做到数据精确查询,但是唯一的缺点就是每次查询都需要进行二次sql查询