当前位置: 首页 > 知识库问答 >
问题:

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

高森
2023-03-14

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

{
    "_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"
        }
    ]
}

由于一些查询将仅包含策略,而一些查询将包含标签和参与者数组,并且考虑到我无法创建具有两个数组的多键索引这一事实,我认为使用索引交叉点将是一个经典场景。

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

以下是索引:

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"
   }

以下是查询:

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();

这是解释的结果:

      "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个文档。

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

有人能帮我遮住我丢失的东西吗?

共有2个答案

阮疏珂
2023-03-14

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

{
    "_id" : ObjectId("54e129c90ab3dc0006000001"),
    "bar" : [
        "hgcmdflitt",
        ...
        "nuzjqxmzot"
    ],
    "foo" : [
        "bxzvqzlpwy",
        ...
        "xcwrwluxbd"
    ]
}

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

db.col.find({"bar":"hgcmdflitt", "foo":"bxzvqzlpwy"}).explain(true)

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

"allPlans" : [
    {
        "cursor" : "BtreeCursor bar_1",
        ...
    },
    {
        "cursor" : "BtreeCursor foo_1",
        ...
    },
    {
        "cursor" : "Complex Plan"
        ...
    }
]

如果您看到一个带有“cursor”的平面:“Complex plan”,这意味着mongo考虑使用索引交点。要找到mongo可能没有决定实际使用该查询计划的原因,请参阅以下答案:MongoDB为什么不使用索引交集?

曾典
2023-03-14

有两件事对你理解这一点非常重要。

>

第二点记录在复合索引的限制中。这实际上指出,即使要“尝试”创建包含所需两个数组字段的复合索引,也不能。这里的问题是,作为一个数组,这为边界键引入了太多的可能性,而多键索引在与标准字段复合使用时已经引入了相当程度的复杂性。

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

可能只有这样,策略索引才是用于这种类型搜索的更好的索引,您可以通过在查询中首先指定该字段来修改它:

db.discussion.find({
    { 
        "policies" : { "$elemMatch" : { 
            "participant_id" : { "$in" : [ 
                "participant-1", 
                "participant-2",
                "participant-3"
            ]},
            "action" : "READ"
        }},
        "tags" : { "$in" : [ "tag-1" , "tag-2" , "tag-3"] }
    }
)

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

如果这实际上对结果没有直接帮助,那么可能需要重新考虑模式,以避免在数组字段或其他类型的“元”字段中包含这些值,这些字段可以通过索引轻松查找。

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

 类似资料:
  • 我有一个MongoDB版本3.0.3集合,其中包含具有2个字段的文档: 数字长id 我在数组上构建了一个多键索引,并通过使用方法确认该索引存在并且是多键的。但是,当我查询数组中特定字段的2个范围的交集时,Mongo不使用此索引,尽管集合中有1,000,000个文档。我可以从方法的输出中看到这一点。更奇怪的是,当我使用指定索引时,Mongo遍历了所有1,000,000个文档和60,000,000个索

  • 问题内容: 我有一个索引元组数组,我想用它从多维numpy数组中选取值, 理解只有在已知的情况下才有效。 有什么提示吗? 问题答案: 您可以将的转置版本转换为元组,然后为矢量化解决方案建立索引-

  • 主要内容:createIndex() 方法,dropIndex() 方法,dropIndexes() 方法,getIndexes() 方法索引是特殊的数据结构,存储在一个方便遍历和读取的数据集合中。索引在任何数据库中都非常重要,通过使用索引,可以大大提高查询语句的执行效率。 举个简单的例子,假如您有一个集合,其中包含了数千甚至上万个没有索引的文档,当我们在集合中查找某个文档时,MongoDB 需要扫描整个集合来寻找所需的文档,这种扫描效率极低,特别是在处理大量的数据时,可能需要花费几十秒甚至几分

  • 本文向大家介绍MongoDB的索引,包括了MongoDB的索引的使用技巧和注意事项,需要的朋友参考一下 1、简介 它就像是一本书的目录,如果没有它,我们就需要对整个书籍进行查找来获取需要的结果,即所说的全盘扫描; 而有了目录(索引)之后就可以通过它帮我们定位到目标所在的位置,快速的获取我们想要的结果。 2、演示 第一步,向用户集合users中插入100W条数据 LZ的渣渣I3和4G内存总共耗时了4

  • 问题内容: 我正在查看数据库中的一个表(我没有创建该表),我发现有两个完全相同的索引(我不知道为什么这样做)只是命名不同,这可以对桌子有负面影响吗? 拿这个例子表: 问题答案: 是的,它可以起作用。 当然,如果使用这两个索引,它们会占用磁盘和内存的额外空间。 但是,它们还会使查询优化器做更多的工作来计算每个SELECT期间每个索引的收益。您拥有的索引越多,需要比较的案例就越多。因此,消除真正的冗余

  • 问题内容: 我面临以下问题,我不确定什么是最佳实践。 考虑下表(该表会变大): id PK | Giver_id FK | FK | 日期 我正在使用InnoDB,据我了解,它会自动为两个外键列创建索引。但是,我还将在需要匹配以下特定组合的情况下进行大量查询: 。 每个这样的组合在表中将是唯一的。 在这些列上添加双列索引有什么好处,还是理论上两个单独的索引足够/相同? 问题答案: 如果您有两个单列