【问题标题】:MemoryError with too large cursor in PyMongo with Pagination带有分页的 PyMongo 中光标过大的 MemoryError
【发布时间】:2018-10-30 09:38:37
【问题描述】:

我有一个我正在尝试分页的对象的光标。我想要的项目总数是 25,但是使用 Django 进行分页的方式需要 whole 光标。在私测中,大概是因为我家的盒子有更多的RAM之类的,我没有这些问题。但是,当推送到只有 2GB 内存的生产机器时,我得到了 MemoryError,可能是因为光标太大。

我可以使用 .limit(25) 和 .skip() 来一次只检索 25 个东西,但是为了让分页工作,我需要对象的总数。不幸的是,.count() 似乎需要获取光标的全部数据。理想情况下,如果我能以某种方式获得查找的大小并且光标中只有 25 个实际对象,我就可以完成这项工作。

所以我想问题是,有没有办法不通过 .count() (获取整个游标的数​​据)来获取游标的大小。

lookup = players.find({field: {'$exists': True}}).sort(field, DESCENDING)
//This returns a MemoryError

lookup = players.find({field: {'$exists': True}}).limit(25).skip(25).sort(field, DESCENDING)
//This does NOT return a Memory Error. However, when I do the following:

lookup.count()
//This also has a MemoryError.

为了澄清,我使用的是 Django 1.5.11 和 pymongo 3.2.1。

【问题讨论】:

    标签: python django mongodb pymongo


    【解决方案1】:

    不要使用skip()limit()进行分页,通常建议使用range queries。这是因为:

    • skip()limit() 必须迭代光标并丢弃结果,这意味着你做了很多不必要的工作。
    • 索引不支持skip()limit()
    • 索引可以非常高效地提供范围查询。

    例如,您可以使用键范围来代替skip()limit()。以id 字段为例,假设id 字段是一个递增的数字:

    db.collection.find({id: {$gte: 0, $lt: 25}, field: {'$exists': True}})
    

    然后您可以创建compound indexid:1, field:1,例如:

    db.collection.createIndex({id:1, field:1})
    

    这将使分页由索引支持,因此快速高效,无需做任何不必要的工作。

    【讨论】:

    • 如果我的 id 字段不是按升序排列的,那如何改变上面的方法?我相信我文档的当前索引是随机生成的 uuid,例如 4321b5c5e4b0cad9a0f3e6a6...
    • 这只是一个例子。您需要根据您的架构以及可用于执行分页的数据来定制解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 2018-04-14
    • 1970-01-01
    • 2019-01-25
    • 2020-07-07
    • 1970-01-01
    • 2020-08-14
    相关资源
    最近更新 更多