MongoDB:简单索引还是复合索引,哪一个是最好的策略?

7gyucuyw  于 2022-11-03  发布在  Go
关注(0)|答案(1)|浏览(151)

我有一个关于索引优化在Mongo中如何工作的问题。
我的应用程序是由客户端(client_id字段)分隔的,他们可以根据自己选择的不同字段自由过滤用户。这就是为什么我在不同的组合上创建了索引,以确保索引的使用。
如果你搜索“client_id + category + address”,是不是一个由3个字段组成的索引被等同地优化为3个简单索引(每个字段一个)?这是我最大的疑问。如果有6个可过滤的字段,有不同的组合。你建议如何创建索引?
谢谢你!

sg24os4d

sg24os4d1#

使用多个索引来执行查询称为索引交集。正如@Sergio Tulentsev在评论中指出的,几乎总是这样,使用单个复合索引(与查询形状紧密对齐)将比依赖索引交集更快。
这是因为与使用复合索引的计划相比,索引交集需要数据库扫描更多的索引键。至少,索引交集需要扫描更多的索引键,并且数据库还必须将这些结果合并在一起。
让我们进一步研究这个问题。假设我们在集合中有以下190文档,其中100分别与查询 predicate 匹配,但只有10同时与查询 predicate 匹配:

test> db.foo.count()
190
test> db.foo.count({x:123})
100
test> db.foo.count({y:456})
100
test> db.foo.count({x:123,y:456})
10

假设存在{ x: 1 }{ y : 1 }的单字段索引,则关联的索引交集计划将根据它们的关联 predicate 扫描这两个字段:

{
    stage: 'IXSCAN',
    ...
    indexBounds: { x: [ '[123, 123]' ] }
  },
  {
    stage: 'IXSCAN',
    ...
    indexBounds: { y: [ '[456, 456]' ] }
  }

为了确保结果完整且正确,数据库需要完成其中一个索引的扫描。根据插入数据的方式,需要检查的索引键总数为110200
第一个
请注意,在此特定示例中,200大于集合中的文档总数。
相比之下,当使用适当的复合索引时,数据库只能精确地检查10相关索引键:

nReturned: 10,
    totalKeysExamined: 10,
    totalDocsExamined: 10,
    ...
        stage: 'IXSCAN',
        ...
        indexBounds: { x: [ '[123, 123]' ], y: [ '[456, 456]' ] },

还要记住MongoDB目前在其page about index intersection上的警告,部分内容如下:
此页面记录查询最佳化工具可能能够使用索引交集的情况。
实际上,查询优化器很少选择使用索引交集的计划。
默认情况下禁用基于哈希的索引交集,并且在计划选择中不支持基于排序的索引交集。
根据该页面,目前最好依赖复合索引,除非您使用的是该页面建议具有不同行为的Atlas搜索。
这样的计划需要扫描更多的索引键的事实可能导致它们在今天的实践中不被非常频繁地选择。
最后,索引键的排序非常重要。这是一个单独的主题,但可以在以下链接中找到关于该主题的一些材料:

@rickhg12hs,here is a playground link提供。有趣的是,它在某种程度上证明了上面的观点,即我们目前不应该依赖于核心MongoDB索引的索引交集。该Playground中的输出显示,在该特定配置中,甚至没有生成任何索引交集计划供查询计划器考虑。
很难解释为什么会出现这种情况,但是还有其他一些奇怪的地方,比如某个层调换了索引边界的键顺序(可能是按字母顺序排列的?):

"indexBounds": {
              "x": [
                "[20.0, 20.0]"
              ],
              "y": [
                "[32.0, 32.0]"
              ]
            },
            "indexName": "y_1_x_1",

相关问题