背景
从上周开始我就一直在做数据清洗的工作,这次算是体会到了什么叫做“抛开数据量谈实现就是耍流氓”。
我设计方案和调试代码连接的都是日常环境的数据库,里面的单表数据量在百级,无论我怎么实现都是瞬间洗完。到了性能测试的时候用的就是性能库,双 11 之前@W君做性能测试的时候,往里面写入了 2000W 的数据,足够我战个痛快。
深坑
一开始的时候,分页查询用的是 limit 子句,SQL 语句形态如下。
select * from table where xxx in (1,2,3) order by id limit #offset#, 200
limit 子句的优点很明显,简单好用。缺点平时不显著,数据量一大就暴露了。数据库会完整扫描 offset 的行,然后继续扫描 200 行之后才把结果集返回。 offset 在 400W 的时候,这样的 SQL 做一次分页查询就已经至少耗时 5s 了。
挣扎
顿时感觉自己陷入了一个泥水坑,赶紧找老司机请教。@Y君给了我一个方案,不使用 limit,直接使用主键索引 + 左右范围查找,SQL 语句形态如下。
select * from table where xxx in (1,2,3) and id >= #minId# and id < #maxId#
其中 minId 和 maxId 由我的代码给出,启动时先算出当前表的 id 范围,然后在此范围内以 200 为步长分页读取,即 maxId - minId = 200,有可能读不到数据,有可能读到 200 条。