首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB -具有两个多键索引的索引交集

MongoDB -具有两个多键索引的索引交集
EN

Stack Overflow用户
提问于 2014-04-18 12:57:48
回答 2查看 1.2K关注 0票数 1

我的集合中有两个数组(一个是嵌入式文档,另一个只是一个简单的字符串集合)。例如,一个文档:

代码语言:javascript
复制
{
    "_id" : ObjectId("534fb7b4f9591329d5ea3d0c"),
    "_class" : "discussion",
    "title" : "A",
    "owner" : "1",
    "tags" : ["tag-1", "tag-2", "tag-3"],
    "creation_time" : ISODate("2014-04-17T11:14:59.777Z"),
    "modification_time" : ISODate("2014-04-17T11:14:59.777Z"),
    "policies" : [
        {
            "participant_id" : "2",
            "action" : "CREATE"
        }, {
            "participant_id" : "1",
            "action" : "READ"
        }
    ]
}

由于一些查询将只包括策略,而另一些查询将包括标记和参与者数组,并且考虑到我不能创建具有两个数组的多键索引的事实,我认为使用Index Intersection将是一个经典的场景。

我正在执行一个查询,但是我看不到交叉点。

以下是索引:

代码语言:javascript
复制
db.discussion.getIndexes()

   {
           "v" : 1,
           "key" : {
                   "_id" : 1
           },
           "name" : "_id_",
           "ns" : "test-fw.discussion"
   },
   {
           "v" : 1,
           "key" : {
                   "tags" : 1,
                   "creation_time" : 1
           },
           "name" : "tags",
           "ns" : "test-fw.discussion",
           "dropDups" : false,
           "background" : false
   },
   {
           "v" : 1,
           "key" : {
                   "policies.participant_id" : 1,
                   "policies.action" : 1
           },
           "name" : "policies",
           "ns" : "test-fw.discussion"
   }

下面是查询:

代码语言:javascript
复制
db.discussion.find({ 
    "$and" : [ 
        { "tags" : { "$in" : [ "tag-1" , "tag-2" , "tag-3"] }},
        { "policies" : { "$elemMatch" : { 
            "$and" : [ 
                { "participant_id" : { "$in" : [ 
                    "participant-1",
                    "participant-2", 
                    "participant-3"
                ]}}, 
                { "action" : "READ"}
            ]
        }}}
    ]
})
.limit(20000).sort({ "creation_time" : 1 }).explain();

下面是解释的结果:

代码语言:javascript
复制
      "clauses" : [
          {
                  "cursor" : "BtreeCursor tags",
                  "isMultiKey" : true,
                  "n" : 10000,
                  "nscannedObjects" : 10000,
                  "nscanned" : 10000,
                  "scanAndOrder" : false,
                  "indexOnly" : false,
                  "nChunkSkips" : 0,
                  "indexBounds" : {
                          "tags" : [
                                  [
                                          "tag-1",
                                          "tag-1"
                                  ]
                          ],
                          "creation_time" : [
                                  [
                                          {
                                                  "$minElement" : 1
                                          },
                                          {
                                                  "$maxElement" : 1
                                          }
                                  ]
                          ]
                  }
          },
          {
                  "cursor" : "BtreeCursor tags",
                  "isMultiKey" : true,
                  "n" : 10000,
                  "nscannedObjects" : 10000,
                  "nscanned" : 10000,
                  "scanAndOrder" : false,
                  "indexOnly" : false,
                  "nChunkSkips" : 0,
                  "indexBounds" : {
                          "tags" : [
                                  [
                                          "tag-2",
                                          "tag-2"
                                  ]
                          ],
                          "creation_time" : [
                                  [
                                          {
                                                  "$minElement" : 1
                                          },
                                          {
                                                  "$maxElement" : 1
                                          }
                                  ]
                          ]
                  }
          },
          {
                  "cursor" : "BtreeCursor tags",
                  "isMultiKey" : true,
                  "n" : 10000,
                  "nscannedObjects" : 10000,
                  "nscanned" : 10000,
                  "scanAndOrder" : false,
                  "indexOnly" : false,
                  "nChunkSkips" : 0,
                  "indexBounds" : {
                          "tags" : [
                                  [
                                          "tag-3",
                                          "tag-3"
                                  ]
                          ],
                          "creation_time" : [
                                  [
                                          {
                                                  "$minElement" : 1
                                          },
                                          {
                                                  "$maxElement" : 1
                                          }
                                  ]
                          ]
                  }
          }
  ],
  "cursor" : "QueryOptimizerCursor",
  "n" : 20000,
  "nscannedObjects" : 30000,
  "nscanned" : 30000,
  "nscannedObjectsAllPlans" : 30203,
  "nscannedAllPlans" : 30409,
  "scanAndOrder" : false,
  "nYields" : 471,
  "nChunkSkips" : 0,
  "millis" : 165,
  "server" : "User-PC:27017",
  "filterSet" : false

查询中的每个标记(tag1、tag-2和tag-3 )都有10K个文档。每个策略({participant-1,READ},{participant-2,READ},{participant-3,READ})有10K个文档。

AND运算符的结果是20K文档。

正如我前面所说的,我不明白为什么两个索引的交集(我指的是策略和标签索引)不起作用。

有人能在我遗漏的东西上遮住一点光吗?

EN

回答 2

Stack Overflow用户

发布于 2014-04-18 13:30:42

实际上,有两件事对您理解这一点很重要。

  • 第一点是,查询优化器在解析查询计划时只能使用one索引,而不能同时使用您指定的两个索引。因此,除非您使用hint显式指定,否则它会根据自己的判断选择最“合适”的一个。交集有些适合,但现在是下一点:
  • 第二点记录在复合索引的limitations中。这实际上表明,即使您“尝试”创建一个包含所需的两个数组字段的复合索引,您也无法做到。这里的问题是,作为一个数组,这为边界键引入了太多的可能性,并且在与标准字段复合使用时,多键索引已经引入了相当程度的复杂性。

组合这两个多键索引的局限性是这里的主要问题,就像它在创建时一样,“组合”这两个索引的复杂性产生了两个许多排列,使其成为一个可行的选择。

可能的情况是,policies索引实际上将更好地用于这种类型的搜索,您可以通过首先在查询中指定该字段来进行修改:

代码语言:javascript
复制
db.discussion.find({
    { 
        "policies" : { "$elemMatch" : { 
            "participant_id" : { "$in" : [ 
                "participant-1", 
                "participant-2",
                "participant-3"
            ]},
            "action" : "READ"
        }},
        "tags" : { "$in" : [ "tag-1" , "tag-2" , "tag-3"] }
    }
)

这是如果这将选择较小的数据范围,它可能会这样做。否则,请使用前面提到的hint修饰符。

如果这实际上不能直接帮助结果,那么可能值得重新考虑模式,使其不涉及将这些值放在数组字段或其他类型的“元”字段中,这些字段可以很容易地通过索引进行查找。

还要注意,在编辑后的表单中,不应该需要所有包装$and语句,因为"and“在MongoDB查询中是隐含的。作为修饰符,仅当您希望在同一字段上两个不同的条件时才需要。

票数 0
EN

Stack Overflow用户

发布于 2015-02-16 07:42:21

在做了一些测试之后,我相信Mongo实际上可以在一个交叉点中使用两个多键索引。我创建了一个具有以下结构的集合:

代码语言:javascript
复制
{
    "_id" : ObjectId("54e129c90ab3dc0006000001"),
    "bar" : [
        "hgcmdflitt",
        ...
        "nuzjqxmzot"
    ],
    "foo" : [
        "bxzvqzlpwy",
        ...
        "xcwrwluxbd"
    ]
}

我在foo和bar上创建了索引,然后运行以下查询。注意传入的"true“来解释。这将启用详细模式。

代码语言:javascript
复制
db.col.find({"bar":"hgcmdflitt", "foo":"bxzvqzlpwy"}).explain(true)

在详细的结果中,您可以找到响应的"allPlans“部分,它将显示mongo考虑的所有查询计划。

代码语言:javascript
复制
"allPlans" : [
    {
        "cursor" : "BtreeCursor bar_1",
        ...
    },
    {
        "cursor" : "BtreeCursor foo_1",
        ...
    },
    {
        "cursor" : "Complex Plan"
        ...
    }
]

如果你看到一个带有"cursor“:"Complex Plan”的计划,那就意味着mongo considered using an index intersection。要找到mongo可能没有决定实际使用该查询计划的原因,请参阅以下答案:Why doesn't MongoDB use index intersection?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23147616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档