前言
此篇博文是 Mongdb 基础系列之一;
这章的内容直接读取官文英文原文比较难懂,所以,单独创建一个章节来整理学习;
本文为作者的原创作品,转载需注明出处;
简介
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.
备注,这里的 bounds 要理解为“边界”的意思;predicates 要理解为“查询条件”的意思;
一系列用来扫描索引的“边界( bounds )”,在一个查询中限定了对一个索引进行扫描(或查询)的部分;
停,这句话怎么理解?index 是一个整体,在查询的时候,通过 bounds 定义了该 index 在查询的过程中被检索( 被查询 )的部分;继续,如果有针对同一个索引的多个“查询条件( predicates )”存在,
停,这句话又该怎么理解?这里的“查询条件( predicates )”对应的其实就是前文所描述的“边界( bounds )”,因为,“查询条件 predicates”定义了“边界 bounds”;MongoDB 为了对 index 生成一个具备更小规模 bounds 的扫描,将会通过“交叉 intersection”或者“复合 compouding”的方式试图去合并这些“边界”;(备注,正如前文笔者所描述的那样,这里的 bounds 指的就是“查询条件 predicates”);因此,最终也就可以得到更少的“查询条件”,其实这么做的意义也就是为了提升对 index 扫描的性能;
Intersect Bounds for Multikey Index (使得 Multikey Index 的边界交叉)
注意,通过简介的分析可知,bounds 的意思就是指“查询条件”的意思;
“边界”交叉的意思就是将多个“查询条件 (multiple bounds)”用 AND 操作符进行链接;比如,我们有这样的查询条件( 既是 bounds ),[ [ 3, Infinity ] ] 和 [ [ -Infinity, 6 ] ],通过交叉以后,我们得到的 bounds 是 [ [ 3, 6 ] ];
假设我们有如下的 survey 数据,
1 | { _id: 1, item: "ABC", ratings: [ 2, 9 ] } |
在 ratings 字段上创建索引,
1 | db.survey.createIndex( { ratings: 1 } ) |
然后执行如下的查询,
1 | db.survey.find( { ratings : { $elemMatch: { $gte: 3, $lte: 6 } } } ) |
上述使用了 $elemMatch,意思是匹配 ratings 字段的时候必须同时满足这两个条件;在 MongoDB 执行查询的时候,会将两个条件分别解释为,
- \$gte: 3 翻译为 [ [ 3, Infinity ] ]
- \$lte: 6 翻译为 [ [ -Infinity, 6 ] ]
然后,将上述的两条查询通过 intersect 操作进行交叉,得到如下的 bound,
1 | ratings: [ [ 3, 6 ] ] |
进行 itersect 操作既交叉动作的前提是多个 bounds 之间有交叉的可行性,比如下面这个例子,就没有交叉的可行性,
1 | db.survey.find( { ratings : { $gte: 3, $lte: 6 } } ) |
Compound Bounds for Multikey Index
Intersect Bounds 主要用于对单个字段
的多个 Bounds 进行合并操作;而 Compound Bounds 则主要是针对多个不同字段(包含一个数组字段)
的查询所进行的查询优化操作;
继续以上述的 survey 数据为例,
1 | { _id: 1, item: "ABC", ratings: [ 2, 9 ] } |
然后,我们在 item 和 ratings 两个字段上同时创建符合索引( Compound Index ),
1 | db.survey.createIndex( { item: 1, ratings: 1 } ) |
注意,这里的 ratings 上的索引是 Multikey Index;
不能交叉的 Compound Bounds
然后,我们执行如下的查询操作
1 | db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } ) |
然后,MongoDB 会分别针对上述两个条件执行如下的查询解析工作,
- 将 item: “XYZ” 条件转换为 [ [ “XYZ”, “XYZ” ] ]
- 将 ratings: { $gte: 3 } 条件转换为 [ [ 3, Infinity ] ]
最终所生成的用于在 index 上查询的条件是,
1 | { item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] } |
为什么第一个条件要这么写呢?item: [ [ “XYZ”, “XYZ” ] ],这样写的目的是既是为了限制其查询的范围;
可被交叉的 Compound Bounds
假如,我们执行下面的查询操作,
1 | db.survey.find( { |
MongoDB 在执行查询的时候,会将上述对 index 的查询优化如下,
1 | "item" : [ [ "L", "Z" ] ], "ratings" : [ [3.0, 6.0] ] |
可见,上述的 Compound Index 是可以通过交叉的方式进行优化的;而需要注意的是,交叉的操作永远是针对同一个字段的不同查询条件进行的;