提问者:小点点

为什么在两个键的查询中,单个索引比复合索引快?(MongoDB,多键)


我创建了4个索引,用于在查询同一文档的两个字段时测试我的集合中的查询性能,其中一个字段是数组(需要一个多键索引)。其中两个指标为单一指标,两个为复合指标。

我很惊讶,因为使用单个索引比使用复合索引能获得更好的性能。我期望使用复合索引获得最佳性能,因为我知道它为两个字段编制索引,从而可以更快地查询。

以下是我的索引:

{    "v" : 1, 
     "key" : { "_id" : 1 }, 
     "ns" : "bt_twitter.mallorca.mallorca", 
     "name" : "_id_"  
}, 
{    "v" : 1, 
     "key" : { "epoch_creation_date" :1 }, 
     "ns" : "bt_twitter.mallorca.mallorca", 
     "name" : "epoch_creation_date_1"  
}, 
{     "v" : 1, 
      "key" : { "related_hashtags" : 1 }, 
      "ns" : "bt_twitter.mallorca.mallorca", 
      "name" : "related_hashtags_1"  
},  
{     "v" : 1, 
      "key" : { "epoch_creation_date" : 1, "related_hashtags" : 1 }, 
      "ns" : "bt_twitter.mallorca.mallorca", 
      "name" : "epoch_creation_date_1_related_hashtags_1"  
}

我的查询和性能指标是(hint参数显示每次查询时使用的索引):

查询1:

active_collection.find(
    {'epoch_creation_date': {'$exists': True}}, 
    {"_id": 0, "related_hashtags":1}
).hint([("epoch_creation_date", ASCENDING)]).explain()

米利斯:237

n已扫描:101226

查询2:

active_collection.find(
    {'epoch_creation_date': {'$exists': True}}, 
    {"_id": 0, "related_hashtags": 1}
).hint([("related_hashtags", ASCENDING)]).explain()

毫秒:1131

n已扫描:306715

质疑三:

active_collection.find(
     {'epoch_creation_date': {'$exists': True}},
     {"_id": 0, "related_hashtags": 1}
).hint([("epoch_creation_date", ASCENDING), ("related_hashtags", ASCENDING)]).explain()

米利斯:935

n已扫描:306715

查询四:

active_collection.find(
     {'epoch_creation_date': {'$exists': True}}, 
     {"_id": 0, "related_hashtags": 1}
).hint([("related_hashtags", ASCENDING),("epoch_creation_date", ASCENDING)]).explain()

米利斯:1165

n已扫描:306715

查询1扫描更少的文档,可能是什么原因使其更快。有人能帮我理解为什么它比复合索引的查询性能更好吗?因此,什么时候使用复合索引比使用单一索引更好呢?

我正在阅读mongo文档,但是这些概念对我来说很难消化。

提前谢谢你。

最新问题(答复Sammaye和Philipp)

这是一个完整的explain()的结果

"cursor" : "BtreeCursor epoch_creation_date_1",
"isMultiKey" : false,
"n" : 101226,
"nscannedObjects" : 101226,
"nscanned" : 101226,
"nscannedObjectsAllPlans" : 101226,
"nscannedAllPlans" : 101226,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 242,
"indexBounds" : {u'epoch_creation_date': [[{u'$minElement': 1}, {u'$maxElement': 1}]]

},
"server" : "vmmongodb:27017"

对于以下查询:

active_collection.find(
{'epoch_creation_date': {'$exists': True}}, 
{"_id": 0, "related_hashtags":1})
.hint([("epoch_creation_date", ASCENDING)]).explain()

共2个答案

匿名用户

您创建了一个复合索引(名为)。

在这两个索引中,只有是有效的,因为您不能同时查询这两个字段。您只查询了一个,这就是。使用执行的字段过滤是在查询找到的文档上执行的。在这一点上,索引就不再有用处了。这意味着上的任何索引都不能提高该查询的性能。复合索引(当您实际使用它时)可能比完全没有索引要好,但不如仅在上的索引好。

匿名用户

好的,在看了这个问题之后,我明白了这个问题。多键索引将为每个多值写入一个索引项。这意味着,如果每个文档的都有3个值,那么索引的大小实际上是3倍,要扫描的值也是3倍(如果我的数学计算加起来的话。。。。。)。

是一个计数器,用于查看一个文档的次数(注释计数器,而不是查看的唯一文档的具体数量),这意味着由于多键索引,您必须扫描的文档数量大约是您在第一次查询时通常扫描的(相同)文档数量的3倍。

对于多键索引,这是一个已知的警告,也是为什么您应该小心这样乱扔它们的原因。

我相信第三个查询速度这么慢的原因是因为多键索引不支持游标,所以MongoDB不能在那里使用覆盖查询。