0

我试图找出在 mongodb 中用于此的最佳索引:

db.articles.find({"images.url":{"$exists":true}, \  
    "source_id": {"$in":[ObjectId("511baf3aa56bde8e94000002"), ObjectId("511baf3aa56bde8e94000999")]}})  \
    .sort({"published_at": -1})

我只想包含存在 images.url 的文章,所以我想知道它是否是稀疏索引?并且不确定要按顺序索引哪些字段,因为我已经阅读了以下不同的指针:

  1. 首先,您将查询确切值的字段。(“images.url”:存在)
  2. 其次,您将对其进行排序的字段。(:published_at)
  3. 最后,您将查询一系列值的字段。(source_id)

另外,在上面的示例中,我不确定 source_id 是否是一个值范围?

我刚在想:

index "images.url": -1, published_at: -1, source_id: 1, {sparse: true}

但我也对最大化索引的排他性感到不安,所以我正在考虑:

index source_id: 1, "images.url": -1, published_at: -1, {sparse: true}
4

1 回答 1

4

如果我们有这样的收藏

{ a:1, b:1, c:1 }
{ a:1, b:1, c:2 }
{ a:1, b:1, c:3 }
{ a:1, b:2, c:1 }
... // all permutations up to:
{ a:3, b:3, c:3 }

以随机顺序想象这个集合

这就是 ({a:1,b:1,c:1}) 上的复合索引的样子

a:  |        1        |        2        |        3        |
    |-----------------+-----------------+-----------------|                   
b:  |  1  |  2  |  3  |  1  |  2  |  3  |  1  |  2  |  3  |
    |-----+-----+-----+-----+-----+-----+-----+-----+-----|
c:  |1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|

对于每个 a,您依次拥有所有 b 和所有 c,好吗?

对于查询:db.xx.find({a:2}).sort({b:1}),您可以看到 b 元素在 a=2; 下方按顺序排列。索引将用于排序 - “scanAndOrder”: explain() 中的 false。如果您的查询是db.xx.find({a:2,c:{$in:[1,3]}}).sort({b:1}) ,也会发生同样的情况

但是这个:db.xx.find({a:{$in:[1,3]}}).sort({b:1}).explain()会告诉你"scanAndOrder" : true,这意味着index 不用于排序(尽管它用于查询) - 从上面的模式中您可以看到,“b”不是 a=[1,3] 的顺序。

这就是为什么索引的有效顺序是:

(1) exact matches (only one!)
(2) sort criteria
(3) matches that point to more than one document

在您的情况下,没有完全匹配;两个查询都返回多个文档。让我们在我们的示例中尝试一下:

db.xx.find({a:{$in:[1,3]},b:{$in:[1,3]}}).sort({c:1}).explain():使用index 用于查询,但不用于排序,它扫描 15 并返回 12 个对象。

db.xx.find({b:{$in:[1,3]},c:{$in:[1,3]}}).sort({a:1}).explain():使用用于查询和排序的索引,但扫描 21 并返回 12 个对象。

哪一个更好?这将取决于您的用例。如果您的查找通常返回许多文档,那么让排序使用索引可能会更有效 - 但如果它通常只返回几个(在许多中),那么您可能更喜欢更有效的扫描。尝试一下,看看使用 explain() 有什么更好的

这有帮助吗?

问候

罗纳德

PS我用它来创建示例集合:

[1,2,3].forEach(function(a){
    [1,2,3].forEach(function(b){
        [1,2,3].forEach(function(c){
            db.xx.insert({a:a,b:b,c:c});
        })
    })
})
于 2013-03-21T12:26:41.467 回答