索引扫描的范围定义了在查询期间要搜索的索引部分。当存在一个索引的多个谓词时,MongoDB将尝试通过相交或复合来组合这些谓词的边界, 以产生具有较小边界的扫描。
边界相交是指AND
多个边界的逻辑合取(即)。例如,给定两个边界
和,边界的交集为
。[ [ 3, Infinity ] ]
[ [ -Infinity, 6 ] ]
[ [ 3, 6 ] ]
给定一个索引数组字段,请考虑一个查询,该查询在数组上指定多个谓词,并且可以使用
多键索引。如果联接连接谓词,则MongoDB可以与多键索引边界
相交
$elemMatch
。
例如,一个集合survey
包含带有一个字段item
和一个数组字段的文档
ratings
:
在
数组上创建一个多键索引ratings
:
以下查询使用$elemMatch
,以要求所述阵列包含至少一个单,这两个条件匹配元素:
将谓词分开:
$gte:
3
[ [ 3, Infinity ] ]
$lte:
6
[ [ -Infinity, 6 ] ]
由于查询用于$elemMatch
连接这些谓词,因此MongoDB可以将边界与以下项相交:
如果查询未使用来加入数组字段的条件
$elemMatch
,则MongoDB无法与多键索引范围相交。考虑以下查询:
该查询在ratings
数组中搜索至少一个大于或等于3的元素以及至少一个小于或等于6的元素。由于单个元素不需要同时满足两个条件,因此MongoDB不会与边界相交,而是使用其中一个或。MongoDB不保证选择这两个界限中的哪一个。[ [ 3,
Infinity ] ]
[ [ -Infinity, 6 ] ]
复合边界是指对复合索引的多个键使用边界
。例如,给定一个复合索引,其的范围为,范围为的范围为,将这些边界组合在一起将导致两个边界的使用:{ a: 1, b: 1 }
a
[ [
3, Infinity ] ]
b
[ [ -Infinity, 6 ]
]
如果MongoDB无法将这两个边界组合在一起,则MongoDB始终通过其前导字段的边界来限制索引扫描,在这种情况下为。a:
[ [ 3, Infinity ] ]
考虑一个复合的多键索引;即复合索引,其中索引字段之一是数组。例如,一个集合survey
包含带有一个字段item
和一个数组字段的文档
ratings
:
在
字段和字段上创建一个复合索引:item
ratings
以下查询在索引的两个键上指定一个条件:
将谓词分开:
item: "XYZ"
[ [ "XYZ", "XYZ" ] ]
ratings: { $gte: 3 }
[ [ 3,
Infinity ] ]
MongoDB可以将两个边界组合起来以使用以下组合的边界:
在版本3.4中更改:仅对于WiredTiger和内存中存储引擎,
从MongoDB 3.4开始,对于使用MongoDB 3.4或更高版本创建的多键索引,MongoDB跟踪哪个或哪些索引字段导致索引成为多键索引。跟踪此信息使MongoDB查询引擎可以使用更严格的索引范围。
前面提到的复合索引位于标量字段[1] item
和数组字段上ratings
:
对于WiredTiger和内存中存储引擎,如果查询操作在MongoDB 3.4或更高版本中创建的复合多键索引的索引标量字段上指定多个谓词,则MongoDB将与该字段的边界相交。
例如,以下操作在标量字段上指定范围查询以及在数组字段上指定范围查询:
MongoDB将与item
to
和rating 的界限相交,以使用以下组合的界限:[ [ "L", "Z" ] ]
[[3.0, 6.0]]
再举一个例子,考虑标量字段属于嵌套文档的位置。例如,一个集合survey
包含以下文档:
创建的标量场的化合物多键索引"item.name"
,
"item.manufactured"
和数组字段ratings
:
考虑以下在标量字段上指定查询谓词的操作:
对于此查询,MongoDB可以使用以下组合范围:
MongoDB的早期版本无法将这些范围组合为标量字段。
[1] | 标量字段是其值既不是文档也不是数组的字段。例如,其值为字符串或整数的字段是标量字段。 标量字段可以是嵌套在文档中的字段,只要该字段本身不是数组或文档即可。例如,在文档中,和是标量字段,其中as 和not。 |
如果数组包含嵌入式文档,则要在嵌入式文档中包含的字段上建立索引,请在索引规范中使用虚线的字段名称。例如,给定以下嵌入式文档数组:
为虚线字段名称score
字段"ratings.score"
。
考虑一个集合,survey2
其中包含带有字段item
和数组字段的文档
ratings
:
在非数组字段以及数组和的
两个字段上创建复合索引:item
ratings.score
ratings.by
以下查询在所有三个字段上指定一个条件:
将谓词分开:
item: "XYZ"
[ [ "XYZ", "XYZ" ] ]
score: { $lte: 5 }
[ [ -Infinity, 5
] ]
by: "anon"
[ "anon", "anon" ]
MongoDB的可以复合边界为item
与键或者为边界"ratings.score"
或界限为"ratings.by"
取决于查询谓词和索引关键字的值,。MongoDB不保证与item
领域的界限。例如,MongoDB将选择将item
边界与"ratings.score"
边界复合
:
或者,MongoDB可以选择将item
范围与
"ratings.by"
范围进行组合:
但是,要将的边界"ratings.score"
与的边界复合"ratings.by"
,查询必须使用$elemMatch
。有关更多信息,请参见
数组中索引字段的复合边界。
要将来自同一数组的索引键的范围组合在一起:
$elemMatch
在该路径上使用的字段上指定谓词
。对于嵌入式文档中的字段,点分的字段名称(例如"a.b.c.d"
)是的字段路径
d
。要复合来自同一数组的索引键的边界,
$elemMatch
必须在直到但不包括字段名称本身的路径上;即"a.b.c"
。
例如,在和字段上创建一个复合索引:ratings.score
ratings.by
字段"ratings.score"
和"ratings.by"
共享字段路径ratings
。以下查询使用$elemMatch
的字段ratings
,以要求所述阵列包含至少一个
单,这两个条件匹配元素:
将谓词分开:
score: { $lte: 5 }
[ -Infinity, 5
]
by: "anon"
[ "anon", "anon" ]
MongoDB可以将两个边界组合起来以使用以下组合的边界:
$elemMatch
¶如果查询未使用来连接索引数组字段的条件$elemMatch
,则MongoDB 无法混合其边界。考虑以下查询:
由于阵列中的单个嵌入的文档并不需要满足两个标准,MongoDB的并没有化合物的界限。使用复合索引时,如果MongoDB无法约束索引的所有字段,则MongoDB始终会约束索引的前导字段,在这种情况下"ratings.score"
:
$elemMatch
在不完整路径上¶如果查询未$elemMatch
在嵌入式字段的路径上指定(最多但不包括字段名),则MongoDB
无法复合来自同一数组的索引键的范围。
例如,一个集合survey3
包含带有一个字段item
和一个数组字段的文档
ratings
:
在和字段上
创建复合索引:ratings.scores.q1
ratings.scores.q2
字段"ratings.scores.q1"
和"ratings.scores.q2"
共享字段路径"ratings.scores"
,并且$elemMatch
必须在该路径上。
但是,以下查询$elemMatch
在必填路径上使用,但未使用:
因此,MongoDB 无法混合边界,并且
"ratings.scores.q2"
在索引扫描期间该字段将不受限制。要增加界限,查询必须$elemMatch
在路径上使用"ratings.scores"
: