我在mongodb中有一个名为product的集合,里面有超过200万个产品,我只想从第一个文档到最后一个文档分页,不需要过滤,不需要排序。
我使用了skip()和limit(),但是随着skip()值的增大,响应时间呈指数增长。
app.get('/products', async (req, res) => {
try {
var query = isNaN(req.query.page) ? 0 : req.query.page <= 0 ? 0 : parseInt(req.query.page) || 0;
const productPerPage = 20;
var totalPages = Product.countDocument();
totalPages = Math.floor(totalPages / 20);
query = query > totalPages ? totalPages : query;
const data = await Product.find()
.sort({_id:1})
.skip(query * productPerPage)
.limit(productPerPage)
res.status(200).render('products', { data, currPage:query, totalPages});
} catch (error) {
console.error(error.message);
res.status(500).send("Internal Server Error");
}
} ```
its working proper but when the database gets larger the response time gets greater.
1条答案
按热度按时间kx5bkwkv1#
使用skip和limit进行分页意味着数据库服务器需要加载匹配的文档,对它们进行排序,然后应用skip和limit。
在
{_id:1}
上使用排序将允许服务器以预先排序的顺序从索引中读取_id值,而不是内存中排序,但是它仍然需要扫描所有值,以便找到第一个要返回的值,即,在第一次调用时,它将从第一个文档开始并返回20,在第二次调用时,它将读取40个文档,丢弃前20个并返回20个,以此类推。2所以在最后一次调用时,它将读取所有200万个文档并丢弃其中的1,999,980个。3这就是为什么它在后面的页面上要慢得多的原因。还有一些性能更好的分页方法,例如,如果应用程序在请求中包含previous _id值,路由可以查询
Product.find({_id:{$gt: ObjectId(req.query.lastseen)}}).sort({_id:1}).limit(productPerPage)
,而不是只请求页码,这样既可以有更可预测的运行时间,又不会因为在调用之间删除文档而丢失文档。