面试题-分表+分页+OrderBy如何实现

"分表后分页",在之前的文章里提过这个点,但是不够详细,最近笔者在工作也遇到了类似的问题,详细的说下这个过程如何实现。

场景:后台系统中的一个订单分页查询功能,乍一看很简单嘛,但是这张订单表分了3张表,分表键是用户标识,比如需要查询第二页的内容并且按照升序排序,该怎么实现呢?

分表后数据分散在各个库,会出现很多种情况:

数据都在1表或都在2表、2表,极端情况

数据在1,2,3表完全一致,极端情况

数据在1,2,3表各自包含一部分,这也是最常见的情况

【假设】一页10条数据,查询第二页的数据,未分表时的实现:

select * from order order by create_time asc limit 10,10;

【假设】分了3张表,分表后的实现:

 实现1:全局查询方式

第一步:分表查询0,10+10的数据

select * from order_1 order by create_time asc limit 0,(10+10);

    select * from order_2 order by create_time asc limit 0,(10+10);

    select * from order_3 order by create_time asc limit 0,(10+10);

第二步:汇总结果,内存排序,获取limit 10,10

    把这个三个查询出的List,汇总到一个List,并且按照时间升序排序,取出第10条到第10+10条的数据。

实现1的优点:满足要求,实现简单,数据完整。

实现1的缺点:需要查询大量的数据,耗时,好网络带宽,汇总结构还需要大量数据的内存排序,耗内存,耗CPU,随着页码增加,比如查第100页,那就需要每张表limit 0,(100+10),很恐怖。

 实现2:二次查找

第一步:limit 10,10中,拿到第一个10除以分表数3,结果取整为3;

第二步:

select * from order_1 order by create_time asc limit 3,10;

    select * from order_2 order by create_time asc limit 3,10;

    select * from order_3 order by create_time asc limit 3,10;

获取到以上3个List,分别取出第一条数据的时间,按照时间比较后取到最小的一条数据,min_create_time;

第三步:

select * from order_1 where between min_create_time and order1_min_create_time;

    select * from order_2 where between min_create_time and order2_min_create_time; 

    select * from order_3 where between min_create_time and order3_min_create_time; 

其中每条Sql里的orderX_min_create_time,是第二步每个List的第一条数据的时间,获取到以上sql的查询结果List.

第四步:

        找到min_create_time在各个表的位置,也就确定了min_create_time在全局表的位置,合并集合就能找到limit 10,10的数据了.

    第二种方式,比较巧妙,在数据极端的情况下会有问题,但是正常来说不会出现这种情况的数据情况,如下图


感谢各位老铁阅读,更多请关注公众号:别明天就今天吧

你可能感兴趣的:(面试题-分表+分页+OrderBy如何实现)