工作中遇到要从网络SQL实例上查几个张表(A\B\C),处理后存到本地Postgres库这么个需求,其中表B过千万(也可能过亿),当然不可能一次性查询,就要用到分页查询了。主流分页方法无非那么几种

1、Not In 大法(据说是效率极低)果断放弃

2、比较主键 top 50000 where max(ID)>50000  order by id  asc(类似)

3、游标法 不太熟悉(看起来也好麻烦)

4、SQL Server 自己生成序号列(要排序)

既然大家都在用,说明很成熟了,也就没想那么多,直接用的方案2(自测时确实比较慢,以为是正常现象,毕竟数据量大),本以为bug修完了交付业务方使用后总算可以喘口气了,结果用了不到一天,就被疯狂吐槽太慢了(业务人员在两千多万的数据中筛出一百多万数据,结果居然等了十个小时)

听完确实比较惊讶,拿到数据复现一下发现问题出在排序上。B表的主键并不连续(如:1、4000、300、127、50000 ),基本是无序的、断号都有。虽然筛出的结果少,每次分页排序耗时大概40S左右,但越往后越慢,导致耗费时间几何倍数上升,用户耐心被一点点磨没了。

问题是找到了,分页数太多不能频繁使用排序(血泪教训),跟同事讨论了一些方法(只有查询权限,有些方法不能用),自己也验证了一下,还是用方法2(主键比较非常快),但不能加排序。从最小主键开始,每次加50000(1-50000、50001-100000),一直到加到最大主键结束,但因为数据无序可能会有空转现象(好在空转也很快,只要次数不多,性能影响很小)

实际用户体验还是不太完美(有时某批数据种类非常多,会空转好多次,明明筛出很少数据用户要等很久)

最近又想起一种思路,但没实践(没机会了,接触不到数据了) 

把这几千万数据的主键查到本地(避免重复排序)、本地再对主键进行排序、分页(根据分页数,取出实际要比较的主键ID,比如位于第50001处的主键ID 和100000处的ID),2千万也就500页,也就一千来个ID,每次分页时用这2个ID,这方法应该效率更高一些