Multikey Index Bounds多键索引边界

On this page本页内容

The bounds of an index scan define the portions of an index to search during a query. 索引扫描的边界定义了查询期间要搜索的索引部分。When multiple predicates over an index exist, MongoDB will attempt to combine the bounds for these predicates, by either intersection or compounding, in order to produce a scan with smaller bounds.当索引上存在多个谓词时,MongoDB将尝试通过交集复合的方式组合这些谓词的边界,以便生成具有较小边界的扫描。

Intersect Bounds for Multikey Index多键索引的相交边界

Bounds intersection refers to a logical conjunction (i.e. AND) of multiple bounds. 边界交集是指多个边界的逻辑连接(即AND)。For instance, given two bounds [ [ 3, Infinity ] ] and [ [ -Infinity, 6 ] ], the intersection of the bounds results in [ [ 3, 6 ] ].例如,给定两个边界[ [ 3, Infinity ] ][ [ -Infinity, 6 ] ],边界的交集产生[ [3, 6 ] ]

Given an indexed array field, consider a query that specifies multiple predicates on the array and can use a multikey index. 给定一个索引数组字段,请考虑一个在数组上指定多个谓词并可以使用多键索引的查询。MongoDB can intersect multikey index bounds if an $elemMatch joins the predicates.如果$elemMatch连接谓词,MongoDB可以与多键索引边界相交。

For example, a collection survey contains documents with a field item and an array field ratings:例如,集合survey包含具有字段项和数组字段ratings的文档:

{ _id: 1, item: "ABC", ratings: [ 2, 9 ] }
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }

Create a multikey index on the ratings array:在评级数组上创建多键索引

db.survey.createIndex( { ratings: 1 } )

The following query uses $elemMatch to require that the array contains at least one single element that matches both conditions:以下查询使用$elemMatch要求数组至少包含一个与两个条件匹配的元素:

db.survey.find( { ratings : { $elemMatch: { $gte: 3, $lte: 6 } } } )

Taking the predicates separately:分别使用谓词:

  • the bounds for the greater than or equal to 3 predicate (i.e. $gte: 3) are [ [ 3, Infinity ] ];大于或等于3谓词(即$gte: 3)的边界为[ [ 3, Infinity ] ]
  • the bounds for the less than or equal to 6 predicate (i.e. $lte: 6) are [ [ -Infinity, 6 ] ].小于或等于6谓词(即$lte:6)的边界为[ [ -Infinity, 6 ] ]

Because the query uses $elemMatch to join these predicates, MongoDB can intersect the bounds to:由于查询使用$elemMatch连接这些谓词,MongoDB可以将边界相交到:

ratings: [ [ 3, 6 ] ]

If the query does not join the conditions on the array field with $elemMatch, MongoDB cannot intersect the multikey index bounds. Consider the following query:如果查询没有将数组字段上的条件与$elemMatch连接起来,MongoDB将无法与多键索引边界相交。考虑以下查询:

db.survey.find( { ratings : { $gte: 3, $lte: 6 } } )

The query searches the ratings array for at least one element greater than or equal to 3 and at least one element less than or equal to 6. 该查询在ratings数组中搜索至少一个大于或等于3的元素和至少一个小于或等于6的元素。Because a single element does not need to meet both criteria, MongoDB does not intersect the bounds and uses either [ [ 3, Infinity ] ] or [ [ -Infinity, 6 ] ]. 因为单个元素不需要同时满足这两个条件,所以MongoDB不与边界相交,而是使用[ [ 3, Infinity ] ][ [ -Infinity, 6 ] ]MongoDB makes no guarantee as to which of these two bounds it chooses.MongoDB不保证它选择这两个边界中的哪一个。

Compound Bounds for Multikey Index多键索引的复合边界

Compounding bounds refers to using bounds for multiple keys of compound index. 复合边界是指对复合索引的多个键使用边界。For instance, given a compound index { a: 1, b: 1 } with bounds on field a of [ [3, Infinity ] ] and bounds on field b of [ [ -Infinity, 6 ]], compounding the bounds results in the use of both bounds:例如,给定一个复合索引{ a: 1, b: 1 },域a的边界为[ [3, Infinity ] ],域b的边界为[ [ -Infinity, 6 ]],复合边界会导致使用两个边界:

{ a: [ [ 3, Infinity ] ], b: [ [ -Infinity, 6 ] ] }

If MongoDB cannot compound the two bounds, MongoDB always constrains the index scan by the bound on its leading field, in this case, a: [ [ 3, Infinity ] ].如果MongoDB不能复合这两个边界,MongoDB总是通过其前导字段上的边界约束索引扫描,在这种情况下,a: [ [ 3, Infinity ] ]

Compound Index on an Array Field数组字段上的复合索引

Consider a compound multikey index; i.e. a compound index where one of the indexed fields is an array. 考虑一个复合多键索引;即,其中一个索引字段是数组的复合索引For example, a collection survey contains documents with a field item and an array field ratings:例如,survey调查包含具有字段item和数组字段ratings的文档:

{ _id: 1, item: "ABC", ratings: [ 2, 9 ] }
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }

Create a compound index on the item field and the ratings field:item字段和ratings字段上创建复合索引

db.survey.createIndex( { item: 1, ratings: 1 } )

The following query specifies a condition on both keys of the index:以下查询指定索引的两个键上的条件:

db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } )

Taking the predicates separately:分别使用谓词:

  • the bounds for the item: "XYZ" predicate are [ [ "XYZ", "XYZ" ] ];item: "XYZ"谓词项的边界为[ [ "XYZ", "XYZ" ] ]
  • the bounds for the ratings: { $gte: 3 } predicate are [ [ 3, Infinity ] ].ratings: { $gte: 3 }谓词的边界为[ [ 3, Infinity ] ]

MongoDB can compound the two bounds to use the combined bounds of:MongoDB可以复合这两个边界以使用以下组合边界:

{ item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] }

Range Queries on a Scalar Indexed Field (WiredTiger)标量索引字段上的范围查询(WiredTiger)

Changed in version 3.4.在版本3.4中更改

For the WiredTiger and In-Memory storage engines only仅适用于WiredTiger和内存存储引擎,

Starting in MongoDB 3.4, for multikey indexes created using MongoDB 3.4 or later, MongoDB keeps track of which indexed field or fields cause an index to be a multikey index. 从MongoDB 3.4开始,对于使用MongoDB 3.4或更高版本创建的多键索引,MongoDB会跟踪哪些索引字段会导致索引成为多键索引。Tracking this information allows the MongoDB query engine to use tighter index bounds.跟踪此信息允许MongoDB查询引擎使用更严格的索引边界。

The aforementioned compound index is on the scalar field [1] item and the array field ratings:上述复合索引位于标量字段[1] item和数组字段ratings上:

db.survey.createIndex( { item: 1, ratings: 1 } )

For the WiredTiger and the In-Memory storage engines, if a query operation specifies multiple predicates on the indexed scalar field(s) of a compound multikey index created in MongoDB 3.4 or later, MongoDB will intersect the bounds for the field.对于WiredTiger和内存存储引擎,如果查询操作在MongoDB 3.4或更高版本中创建的复合多键索引的索引标量字段上指定多个谓词,MongoDB将与字段的边界相交。

For example, the following operation specifies a range query on the scalar field as well as a range query on the array field:例如,以下操作指定标量字段上的范围查询以及数组字段上的范围查询:

db.survey.find( {
   item: { $gte: "L", $lte: "Z"}, ratings : { $elemMatch: { $gte: 3, $lte: 6 } }
} )

MongoDB will intersect the bounds for item to [ [ "L", "Z" ] ] and ratings to [[3.0, 6.0]] to use the combined bounds of:MongoDB将item的边界与[ [ "L", "Z" ] ]相交,将rating的边界与[[3.0, 6.0]]相交,以使用以下组合边界:

"item" : [ [ "L", "Z" ] ], "ratings" : [ [3.0, 6.0] ]

For another example, consider where the scalar fields belong to a nested document. 例如,考虑标量字段属于嵌套文档的位置。For instance, a collection survey contains the following documents:例如,集合survey包含以下文档:

{ _id: 1, item: { name: "ABC", manufactured: 2016 }, ratings: [ 2, 9 ] }
{ _id: 2, item: { name: "XYZ", manufactured: 2013 },  ratings: [ 4, 3 ] }

Create a compound multikey index on the scalar fields "item.name", "item.manufactured", and the array field ratings :在标量字段"item.name""item.manufactured"和数组字段ratings上创建复合多键索引:

db.survey.createIndex( { "item.name": 1, "item.manufactured": 1, ratings: 1 } )

Consider the following operation that specifies query predicates on the scalar fields:考虑以下在标量字段上指定查询谓词的操作:

db.survey.find( {
   "item.name": "L" ,
   "item.manufactured": 2012
} )

For this query, MongoDB can use the combined bounds of:对于此查询,MongoDB可以使用以下组合边界:

"item.name" : [ ["L", "L"] ], "item.manufactured" : [ [2012.0, 2012.0] ]

Earlier versions of MongoDB cannot combine these bounds for the scalar fields.早期版本的MongoDB无法组合标量字段的这些边界。

[1] A scalar field is a field whose value is neither a document nor an array; e.g. a field whose value is a string or an integer is a scalar field.标量字段是其值既不是文档也不是数组的字段;值为字符串或整数的字段是标量字段。A scalar field can be a field nested in a document, as long as the field itself is not an array or a document. 标量字段可以是嵌套在文档中的字段,只要字段本身不是数组或文档。For example, in the document { a: { b: { c: 5, d: 5 } } }, c and d are scalar fields where as a and b are not.例如,在文档{ a: { b: { c: 5, d: 5 } } }中,cd是标量字段,其中a和b不是。

Compound Index on Fields from an Array of Embedded Documents嵌入文档数组中字段的复合索引

If an array contains embedded documents, to index on fields contained in the embedded documents, use the dotted field name in the index specification. 如果数组包含嵌入文档,要对嵌入文档中包含的字段进行索引,请在索引规范中使用虚线字段名称For instance, given the following array of embedded documents:例如,给定以下嵌入文档数组:

ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ]

The dotted field name for the score field is "ratings.score".score字段的dotted字段名称为"ratings.score"

Compound Bounds of Non-array Field and Field from an Array非数组字段和数组字段的复合边界

Consider a collection survey2 contains documents with a field item and an array field ratings:假设集合survey2包含具有字段item和数组字段ratings的文档:

{
  _id: 1,
  item: "ABC",
  ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ]
}
{
  _id: 2,
  item: "XYZ",
  ratings: [ { score: 5, by: "anon" }, { score: 7, by: "wv" } ]
}

Create a compound index on the non-array field item as well as two fields from an array ratings.score and ratings.by:在非数组字段item以及数组ratings.scoreratings.by中的两个字段上创建复合索引

db.survey2.createIndex( { "item": 1, "ratings.score": 1, "ratings.by": 1 } )

The following query specifies a condition on all three fields:以下查询指定了所有三个字段的条件:

db.survey2.find( { item: "XYZ",  "ratings.score": { $lte: 5 }, "ratings.by": "anon" } )

Taking the predicates separately:分别使用谓词:

  • the bounds for the item: "XYZ" predicate are [ [ "XYZ", "XYZ" ] ];item: "XYZ"谓词的边界为[ [ "XYZ", "XYZ" ] ]
  • the bounds for the score: { $lte: 5 } predicate are [ [ -Infinity, 5 ] ];score: { $lte: 5 }谓词的边界为[ [ -Infinity, 5 ] ]
  • the bounds for the by: "anon" predicate are [ "anon", "anon" ].by: "anon"谓词的边界为[ "anon", "anon" ]

MongoDB can compound the bounds for the item key with either the bounds for "ratings.score" or the bounds for "ratings.by", depending upon the query predicates and the index key values. MongoDB可以根据查询谓词和索引键值,将item键的边界与"ratings.score"的边界或"ratings.by"的边界复合。MongoDB makes no guarantee as to which bounds it compounds with the item field. MongoDB不保证它与item字段复合的边界。For instance, MongoDB will either choose to compound the item bounds with the "ratings.score" bounds:例如,MongoDB将选择将item边界与"ratings.score"边界复合:

{
  "item" : [ [ "XYZ", "XYZ" ] ],
  "ratings.score" : [ [ -Infinity, 5 ] ],
  "ratings.by" : [ [ MinKey, MaxKey ] ]
}

Or, MongoDB may choose to compound the item bounds with "ratings.by" bounds:或者,MongoDB可以选择将item边界与"ratings.by"边界复合:

{
  "item" : [ [ "XYZ", "XYZ" ] ],
  "ratings.score" : [ [ MinKey, MaxKey ] ],
  "ratings.by" : [ [ "anon", "anon" ] ]
}

However, to compound the bounds for "ratings.score" with the bounds for "ratings.by", the query must use $elemMatch. 但是,要将"ratings.score"的边界与"ratings.by"的边界复合,查询必须使用$elemMatchSee Compound Bounds of Index Fields from an Array for more information.有关详细信息,请参阅数组中索引字段的复合边界

Compound Bounds of Index Fields from an Array数组中索引字段的复合边界

To compound together the bounds for index keys from the same array:要将同一数组中索引键的边界组合在一起,请执行以下操作:

  • the index keys must share the same field path up to but excluding the field names, and索引键必须共享相同的字段路径,但不包括字段名,以及
  • the query must specify predicates on the fields using $elemMatch on that path.查询必须在该路径上使用$elemMatch在字段上指定谓词。

For a field in an embedded document, the dotted field name, such as "a.b.c.d", is the field path for d. 对于嵌入文档中的字段,虚线字段名(如"a.b.c.d")是d的字段路径。To compound the bounds for index keys from the same array, the $elemMatch must be on the path up to but excluding the field name itself; i.e. "a.b.c".要复合来自同一数组的索引键的边界,$elemMatch必须位于到但不包括字段名本身的路径上;即"a.b.c"

For instance, create a compound index on the ratings.score and the ratings.by fields:例如,在ratings.scoreratings.by字段上创建复合索引

db.survey2.createIndex( { "ratings.score": 1, "ratings.by": 1 } )

The fields "ratings.score" and "ratings.by" share the field path ratings. "ratings.score""ratings.by"字段共享字段路径评级。The following query uses $elemMatch on the field ratings to require that the array contains at least one single element that matches both conditions:以下查询在字段ratings上使用$elemMatch来要求数组至少包含一个匹配这两个条件的元素:

db.survey2.find( { ratings: { $elemMatch: { score: { $lte: 5 }, by: "anon" } } } )

Taking the predicates separately:分别使用谓词:

  • the bounds for the score: { $lte: 5 } predicate are [ [ -Infinity, 5 ] ];score: { $lte: 5 }谓词的边界是[ [ -Infinity, 5 ] ]
  • the bounds for the by: "anon" predicate are [ [ "anon", "anon" ] ].by: "anon"谓词的边界是[ [ "anon", "anon" ] ]

MongoDB can compound the two bounds to use the combined bounds of:MongoDB可以复合这两个边界以使用以下组合边界:

{ "ratings.score" : [ [ -Infinity, 5 ] ], "ratings.by" : [ [ "anon", "anon" ] ] }

Query Without $elemMatch不带$elemMatch的查询

If the query does not join the conditions on the indexed array fields with $elemMatch, MongoDB cannot compound their bounds. 如果查询没有将索引数组字段上的条件与$elemMatch连接起来,MongoDB无法复合它们的边界。Consider the following query:考虑以下查询:

db.survey2.find( { "ratings.score": { $lte: 5 }, "ratings.by": "anon" } )

Because a single embedded document in the array does not need to meet both criteria, MongoDB does not compound the bounds. 因为数组中的单个嵌入文档不需要满足这两个条件,所以MongoDB不会复合边界。When using a compound index, if MongoDB cannot constrain all the fields of the index, MongoDB always constrains the leading field of the index, in this case "ratings.score":使用复合索引时,如果MongoDB无法约束索引的所有字段,MongoDB始终约束索引的前导字段,在本例中为"ratings.score"

{
  "ratings.score": [ [ -Infinity, 5 ] ],
  "ratings.by": [ [ MinKey, MaxKey ] ]
}

$elemMatch on Incomplete Path不完全路径上的$elemMatch

If the query does not specify $elemMatch on the path of the embedded fields, up to but excluding the field names, MongoDB cannot compound the bounds of index keys from the same array.如果查询未在嵌入字段的路径上指定$elemMatch,直到但不包括字段名,MongoDB无法复合来自同一数组的索引键的边界。

For example, a collection survey3 contains documents with a field item and an array field ratings:例如,集合survey3包含具有字段item和数组字段ratings的文档:

{
  _id: 1,
  item: "ABC",
  ratings: [ { scores: [ { q1: 2, q2: 4 }, { q1: 3, q2: 8 } ], loc: "A" },
             { scores: [ { q1: 2, q2: 5 } ], loc: "B" } ]
}
{
  _id: 2,
  item: "XYZ",
  ratings: [ { scores: [ { q1: 7 }, { q1: 2, q2: 8 } ], loc: "B" } ]
}

Create a compound index on the ratings.scores.q1 and the ratings.scores.q2 fields:ratings.scores.q1ratings.scores.q2字段上创建复合索引

db.survey3.createIndex( { "ratings.scores.q1": 1, "ratings.scores.q2": 1 } )

The fields "ratings.scores.q1" and "ratings.scores.q2" share the field path "ratings.scores" and the $elemMatch must be on that path.字段"ratings.scores.q1""ratings.scores.q2"共享字段路径"ratings.scores",并且$elemMatch必须位于该路径上。

The following query, however, uses an $elemMatch but not on the required path:但是,以下查询使用$elemMatch,但不在所需路径上:

db.survey3.find( { ratings: { $elemMatch: { 'scores.q1': 2, 'scores.q2': 8 } } } )

As such, MongoDB cannot compound the bounds, and the "ratings.scores.q2" field will be unconstrained during the index scan. 因此,MongoDB无法复合边界,"ratings.scores.q2"字段在索引扫描期间将不受约束。To compound the bounds, the query must use $elemMatch on the path "ratings.scores":要复合边界,查询必须在路径"ratings.scores"上使用$elemMatch

db.survey3.find( { 'ratings.scores': { $elemMatch: { 'q1': 2, 'q2': 8 } } } )
←  Multikey IndexesText Indexes →