查询优化
索引通过减少查询操作需要处理的数据量来提高读取操作的效率。这简化了在 MongoDB 中执行查询的相关工作。
创建索引以支持读取操作
如果您的应用程序查询特定字段或字段集合上的设立,则查询字段上的索引或字段设立上的复合索引可以阻止查询扫描整个集合以查找并返回查询结果。 有关索引的更多信息,请参阅MongoDB中索引的完整文档。
例子
某一应用程序将针对 type
字段来查询 inventory
集合。type
字段的值由用户决定。
var typeValue = <someUserInput>; db.inventory.find( { type: typeValue } );
要提高此查询的性能,请向type
字段上的inventory
集合添加升序或降序索引。 [ 1 ]在 mongosh
中,您可以使用db.collection.createIndex()
方法创建索引:
db.inventory.createIndex( { type: 1 } )
该索引可防止上述对 type
的查询扫描整个集合以返回结果。
如要分析使用索引进行查询的性能,请参阅解释“解释计划结果”。
除了优化读取操作之外,索引还支持排序操作并能够实现更高效的存储利用率。有关创建索引的更多信息,请参阅 db.collection.createIndex()
和 索引。
[1] | 对于单字段索引,升序和降序之间的选择并不重要。对于复合索引,选择很重要。详情请参见索引顺序。 |
查询选择性
查询选择性是指查询谓词排除或过滤出集合中文档的程度。查询选择性可以确定查询能否有效地使用索引,抑或根本不使用索引。
选择性更强的查询匹配的文档比例更小。例如,唯一的 _id
字段上的相等匹配具有高度选择性,因为它最多可以匹配一个文档。
选择性较低的查询会匹配更大比例的文档。选择性较低的查询无法有效使用索引,甚至根本不使用索引。
例如,不等于操作符 $nin
和 $ne
的选择性不高,因为它们通常匹配很大一部分索引。因此,在许多情况下,带有索引的 $nin
或 $ne
查询的性能可能不会比必须扫描集合中所有文档的 $nin
或 $ne
查询更好。
regular expressions
的选择性取决于表达式本身。有关详情,请参阅正则表达式和索引使用。
覆盖查询
覆盖查询是可以完全使用索引来满足并且不必检查任何文档的查询。满足以下所有条件时,索引将覆盖查询:
查询中的所有字段都是索引的一部分,并且
结果中返回的所有字段都位于同一索引中。
查询中没有字段等于
null
(即{"field" : null
} 或 {"field" : {$eq : null}}
)。
例如,集合inventory
在type
和item
字段上具有以下索引:
db.inventory.createIndex( { type: 1, item: 1 } )
该索引将查询 type
和 item
字段并仅返回 item
字段的下列操作:
db.inventory.find( { type: "food", item:/^c/ }, { item: 1, _id: 0 } )
为了使指定索引覆盖查询,投影文档必须显式指定 _id: 0
以从结果中排除 _id
字段,因为索引不包含 _id
字段。
嵌入式文档
索引可以涵盖对嵌入式文档中字段的查询。
例如,考虑一个包含以下形式文档的集合 userdata
:
{ _id: 1, user: { login: "tester" } }
该集合包含以下索引:
{ "user.login": 1 }
{ "user.login": 1 }
索引将涵盖以下查询:
db.userdata.find( { "user.login": "tester" }, { "user.login": 1, _id: 0 } )
注意
要为嵌入式文档中的字段编制索引,请使用点符号。
多键覆盖
多键索引如果要追踪哪个或哪些字段致使其成为多键,则其可涵盖对非数组字段的查询。
多键索引无法涵盖对数组字段的查询。
性能
由于索引包含查询所需的所有字段,因此,MongoDB 可以只使用索引来匹配查询条件并返回结果。
仅查询索引比查询索引之外的文档要快得多。索引键通常小于它们编目的文档,并且索引通常在 RAM 中可用或按顺序存储在磁盘上。
限制
带索引字段的限制
分片集合限制
explain
要确定查询是否属于覆盖查询,请使用 db.collection.explain()
或 explain()
方法,并查看结果。