带有分页的PyMongo中游标太大的MemoryError

时间:2018-05-20 16:12:44

标签: python django mongodb pymongo

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

我可以使用.limit(25)和.skip()来一次只检索25个东西,但是为了让Pagination工作,我需要对象的总数。不幸的是,.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。

1 个答案:

答案 0 :(得分:1)

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

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

例如,您可以使用一系列密钥代替skip()limit()。以id字段为例,假设id字段的数字不断增加:

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

然后,您可以创建id:1, field:1 db.collection.createIndex({id:1, field:1}) ,例如:

typedef struct {
    node *head;
    size_t size;
} stack_t;

size_t stack_size(stack_t *stack) {
    return stack->size;
}

bool is_empty(stack_t *stack) {
    return stack_size(stack) == 0;
}

stack_t *stack_create(void) {
    stack_t *stack = malloc(sizeof(stack_t));
    stack->size = 0;
    stack->head = NULL;
    return stack;
}

void push(stack_t *stack, int data) {
    node *new_node = malloc(sizeof(struct nodeRec));
    new_node->item = data;
    new_node->next = stack->head;
    stack->head = new_node;
    stack->size++;
}

int pop(stack_t *stack) {
    assert(!is_empty(stack));
    node *old_head = stack->head;
    stack->head = stack->head->next;
    int ret = old_head->item;
    free(old_head);
    stack->size--;
    return ret;
}

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