提问者:小点点

使用MongoDb C驱动程序查询大型集合与shell不同


Windows 7 64 SP1--MongoDB 2.2.0-rc2--Boost 1.42--MSVS 2010 Ultimate--C驱动程序

在“Mongo in Action”之后,在shell中:

for(i=0; i<200000; i++){
  db.numbers.save({num: i});
}

db. number.find()显示:

{ "_id": ObjectId("4bfbf132dba1aa7c30ac830a"),"num" : 0 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830b"),"num" : 1 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830c"),"num" : 2 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830d"),"num" : 3 }
...

所以,在C中复制:

// Insert 200,000 documents
for ( int i = 0; i < 200000 ; i++)
  c.insert(dc,BSON(GENOID << "num" << i));

//Display the first 20 documents
Query qu = BSONObj();
auto_ptr<DBClientCursor> cursor = c.query(dc,qu); 
for ( int i = 0 ; i < 20 ; i++){
  cout << cursor->next().toString() << endl;
}

输出:

{ "_id" : ObjectId("504bab737ed339cef0e26829"), "num" : 199924 }
{ "_id" : ObjectId("504bab737ed339cef0e2682a"), "num" : 199925 }
{ "_id" : ObjectId("504bab737ed339cef0e2682b"), "num" : 199926 }
{ "_id" : ObjectId("504bab737ed339cef0e2682c"), "num" : 199927 }
....

在shell中调用db. number.find()具有相同的输出。为什么它不以{"num":0}开头?它存在:

> db.numbers.find({"num" : 0})
{ "_id" : ObjectId("504bab417ed339cef0df5b35"), "num" : 0 }

{"num": 0}的_id在{"num":199924}的_id之前

还有一个关于“_id”的索引:

> db.numbers.getIndexes()
[
    {
            "v" : 1,
            "key" : {
                    "_id" : 1
            },
            "ns" : "learning.numbers",
            "name" : "_id_"
    }
]

如果我添加按_id排序,将查询代码更改为:

auto_ptr<DBClientCursor> cursor = c.query(dc,qu.sort("_id")); 

然后它按顺序打印:

{ "_id": ObjectId("4bfbf132dba1aa7c30ac830a"),"num" : 0 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830b"),"num" : 1 }
...

这不会发生在较小的文档集合(例如200个)中。

问题是:为什么C查询似乎没有在_id上使用集合的索引?或者还有什么可以解释这种明显的异常(或者我缺乏理解?


共2个答案

匿名用户

索引和排序是不同的概念。您可以在索引中查找数据而无需对结果进行排序;您也可以在不使用索引的情况下对结果进行排序(尽管不建议这样做)。

由于您没有为find()指定排序顺序,因此结果将按自然顺序返回。对于仅插入文档(且从未删除或更新)的集合,自然顺序应近似于插入顺序(除非您碰巧使用的是按插入顺序维护的上限集合)。

一旦你开始删除文档或更新它们(这可能会导致它们被移动),MongoDB的预分配数据文件中就会产生空闲空间“间隙”。MongoDB将重用空闲空间进行新的文档插入/移动…因此随着时间的推移,自然顺序将不再匹配插入顺序。

如果您期待特定排序顺序的结果,则必须将其包含在查询中。

匿名用户

@stenni谢谢——这些“差距”是问题所在,并让我找到了解决方案。查询时,shell中的自然顺序似乎比C驱动程序更“自然”,后者以一个非常大的“num”开头。然而,错误在于我的方法论:

  1. 在shell中插入200000个文档。
  2. db. number.find();列出的第一个文档是{"num":0}
  3. db。数字。删除()
  4. 使用C驱动程序插入200000个文档
  5. db. number.find();列出的第一个文档是{"num":有一些VeryLargeNumber}

相反,我应该使用db. number.drop(),实际上是删除集合。这样做意味着第5步列出的第一个文档是{"num":0}db.numbers.删除显然保留了空白。

相关问题