采用Seek Method加速分页

凡事作过页面的,通常对分页不会陌生,也不会以为它有多难:就是limit + offset的组合就能够了呀。可是,危险每每都是从最不起眼的地方开始的。在这里,我先说一下我以前在用MongoDB时遇到的问题。这类问题一样会出如今这种分页方式上。sql

当时,我须要对于MongoDB中的数据进行处理,每次处理一批,也至关因而按页来操做数据啦。这个没啥难度,直接使用API中的find + skip + limit就能够轻易搞定。迅速把程序写完以后就开始拿产品库开搞了。刚开始一切正常,可过了没多久,就发现整个程序的性能降低了。进入Mongo一查,发现是Table Scan。哇,那个collection中有上千万的数据啊!性能

此处略去3000字。fetch

总之,问题最后解决了,程序又运行如飞。而解决之道很简单:只用find + limit,再也不使用skip(缘由本身想)。只不过在find中加了一个条件:上一批的最后一个document的_id。整个代码形似(groovy代码):code

if (docId) {
    batch = collection.find(['_id': ['$gt': docId]] as Document).limit(BATCH_SIZE)
} else {
    batch = collection.find().limit(BATCH_SIZE)
}
docId = batch[-1]['_id']

它的原理很简单,其实就是利用能够利用的index来加速分页。这种思想跟今天看到的文章的思路一模一样,再也不使用offset,寻找能达到一样效果的index,用它来助力搜索。所以,文中给出的方案跟上面的代码相似:blog

SELECT ...
  FROM ...
 WHERE ...
   AND id < ?last_seen_id
 ORDER BY id DESC
 FETCH FIRST 10 ROWS ONLY

这种分页方式被称为“seek method”,其中的id被称为“seek predicate”。典型的seek predicate还能够是日期。须要提醒的是,seek predicate上须要有index才有意义,并且它能够有多列!采用这种方式的分页能够避免上述分页的潜在危险:当页数达到必定量以后,分页速度会严重降低。ip

关于seek method,还能够参考下面的文章:get

相关文章
相关标签/搜索