【问题标题】:Why does direction of index matter in MongoDB?为什么索引的方向在 MongoDB 中很重要?
【发布时间】:2012-05-06 22:20:38
【问题描述】:

引用docs

创建索引时,与键关联的数字指定 索引的方向,因此它应该始终为 1(升序)或 -1 (下降)。方向对于单键索引或 随机访问检索,但如果您正在进行排序或 复合索引的范围查询。

但是,我看不出为什么索引的方向对复合索引很重要。有人可以提供进一步的解释(或示例)吗?

【问题讨论】:

    标签: mongodb performance sorting indexing query-optimization


    【解决方案1】:

    MongoDB 以某种方式连接复合键并将其用作 BTree 中的键。

    查找单个项目时 - 树中节点的顺序无关紧要。

    如果您要返回一系列节点 - 彼此靠近的元素将位于树的相同分支下。节点在范围内越近,检索它们的速度就越快。

    使用单个字段索引 - 顺序无关紧要。如果它们按升序排列,它们也将按降序排列。

    当您拥有复合键时 - 顺序开始变得重要。

    例如,如果键是 A 升序 B 升序,则索引可能如下所示:

    行 A B 1 1 1 2 2 6 3 2 7 4 3 4 5 3 5 6 3 6 7 5 1

    对 A 升序 B 降序的查询将需要乱序跳转索引以返回行,并且会更慢。例如它将返回 Row 1, 3, 2, 6, 5, 4, 7

    与索引顺序相同的范围查询只会以正确的顺序依次返回行。

    在 BTree 中查找记录需要 O(Log(n)) 时间。按顺序查找记录范围只需 OLog(n) + k,其中 k 是要返回的记录数。

    如果记录乱序,代价可能高达OLog(n) * k

    【讨论】:

    • 结果行应该是1, 3, 2, 6, 5, 4, 7?
    • 我仍然认为它没有理由变慢。只有算法应该不同(对于 A 中的每组值,它应该跳到组的末尾并以相反的顺序处理它),但是由于 MongoDB 索引在内存中,因此对速度应该没有明显的影响。此外,RDBMS 对索引的方向一无所知,并且那里的情况非常相似?
    • 它之所以会影响性能,是因为它不像简化示例那样只是内存中的顺序列表。它实际上是一棵加权树。跳出顺序将涉及再次遍历树。 RDMS 绝对具有索引顺序。
    • 按顺序从 BTree 中获取节点就像沿着每个叶子移动直到用完,然后上一层并下一个分支一样简单。它是 O(n) 乱序它更占用 CPU。
    • 这仍然是对布尔字段进行索引/排序的问题吗?如果我只想获取用户的“活动”项目,我应该创建索引{ user_id: 1, active: 1 }{ user_id: 1, active: -1 } 还是有关系? (假设active 可以是真/假并且数据库中没有空值)
    【解决方案2】:

    您正在寻找的简单答案是方向仅在您对两个或多个字段进行排序时才重要

    如果你在{a : 1, b : -1}上排序:

    索引{a : 1, b : 1}慢于索引{a : 1, b : -1}

    【讨论】:

    • @MarkPieszak 因为整个排序必须在内存中完成,使得索引无用
    • @Sammaye 我认为这是正确的想法,尽管我不确定它是否是 整个 类型。我必须查看实现才能知道它是如何工作的,但我认为结果可以单独按 a 排序,然后是额外的 b 排序需要在内存中完成。
    • 嗯,奇怪的是上次我检查代码时由于排序方式而丢弃了部分排序,但是嗯,也许它已经改变了
    • 如果我在{a: -1, b: -1} 上排序,我应该有{a: -1, b: -1} 索引还是{a: 1, b: 1} 就足够了。
    • @Hussain 在您的示例中,{a: 1, b: 1} 索引应该足够了,因为完全反转索引就可以了。例如{a: 1} 上的索引可用于对 {a: -1} 进行排序
    【解决方案3】:

    为什么要索引

    了解两个关键点。

    1. 虽然有索引总比没有索引好,但正确的索引比任何一个都好。
    2. MongoDB 每次查询仅使用一个索引,从而使复合索引具有适当的字段排序,您可能想要使用。

    索引不是免费的。它们占用内存,并在执行插入、更新和删除时施加性能损失。通常,性能损失可以忽略不计(尤其是与读取性能的提升相比),但这并不意味着我们不能聪明地创建索引。

    如何索引

    确定应将哪些字段组编入索引是为了了解您正在运行的查询。用于创建索引的字段顺序至关重要。好消息是,如果你把顺序弄错了,索引根本不会被使用,所以用解释很容易发现。

    为什么要排序

    您的查询可能需要排序。但是排序可能是一项代价高昂的操作,因此将您正在排序的字段视为您正在查询的字段非常重要。所以如果它有索引会更快。但是有一个重要的区别,您要排序的字段必须是索引中的最后一个字段。此规则的唯一例外是,如果该字段也是您的查询的一部分,则 must-be-last-rule 不适用。

    如何排序

    您可以对索引的所有键或子集指定排序;但是,排序键的列出顺序必须与它们在索引中出现的顺序相同。例如,索引键模式 { a: 1, b: 1 } 可以支持对 { a: 1, b: 1 } 的排序,但不支持对 { b: 1, a: 1 } 的排序。

    排序必须为其所有键指定相同的排序方向(即升序/降序)作为索引键模式,或为其所有键指定反向排序方向作为索引键模式。例如,索引键模式 { a: 1, b: 1 } 可以支持对 { a: 1, b: 1 } 和 { a: -1, b: -1 } 的排序,但不支持对 { a: -1 , b: 1 }。

    假设有这些索引:

    { a: 1 }
    { a: 1, b: 1 }
    { a: 1, b: 1, c: 1 }
    
    Example                                                    Index Used
    db.data.find().sort( { a: 1 } )                            { a: 1 }
    db.data.find().sort( { a: -1 } )                           { a: 1 }
    db.data.find().sort( { a: 1, b: 1 } )                      { a: 1, b: 1 }
    db.data.find().sort( { a: -1, b: -1 } )                    { a: 1, b: 1 }
    db.data.find().sort( { a: 1, b: 1, c: 1 } )                { a: 1, b: 1, c: 1 }
    db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } )   { a: 1, b: 1 }
    

    【讨论】:

    • 我知道这是一个例子,但如果有索引{ a: 1, b: 1, c: 1 } 你真的需要索引{ a: 1}{ a: 1, b: 1} 或索引{ a: 1, b: 1, c: 1 } 涵盖所有情况吗?如果查询总是使用相同的排序:1 在查询中没有排序 -1
    • 如果有很多查询只在属性“a”上工作,使用属性“a”的索引搜索数据库引擎比使用3个属性“a”的索引搜索要快, 'b','c'。因为索引大小会增加,计数也会增加。前任。如果书中有20章。所以转到第 3 章然后转到特定页面会更快。 @LukasLiesis
    • 我应该同时创建{ date: -1, _id: 1 }{ date: 1, _id: -1 } 还是只创建一个?
    • 我发现其中一个就足够了。看这里docs.mongodb.com/manual/core/index-compound/#sort-order
    猜你喜欢
    • 1970-01-01
    • 2015-08-01
    • 2013-05-28
    • 2013-03-19
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 2021-08-09
    相关资源
    最近更新 更多