交叉索引(index intersection)
自 2.6 版本的新功能。
MongoDB 可以用多个索引交叉使用来满足查询(解释一)。通常,每一个交叉索引包含了两个索引;然而,MongoDB 可以使用多个甚至嵌套的交叉索引来完成查询。
解释一: 在以前的版本中,MongoDB 一般只能用一个索引来满足大多数的查询。一个例外是用
$or
的子句查询,它可以为每$or
子句提供一个索引。
为了理解交叉索引,考虑一个集合 orders
有以下索引:
{ qty: 1 }
{ item: 1 }
MongoDB 可以用两个索引的交叉来支持以下查询:
db.orders.find( { item: "abc123", qty: { $gt: 15 } } )
为确认 MongoDB 是否使用了交叉索引,可以用 explain()
函数看结果是否包含一个 AND_SORTED
stage 或一个 AND_HASH
stage。
索引前缀交叉
用交叉索引,MongoDB 即可以用整个索引的交叉也可以用前缀索引的交叉。前缀索引(index prefix)是复合索引(compound index)的子集,由索引从开始字段起始的一个或多个字段组成。
考虑在 orders
集合上有以下索引:
{ qty: 1 }
{ status: 1, ord_date: -1 }
为了满足下列指定在既有 qty
又有 status
字段的查询条件,MongoDB 可以用这两个索引的交叉。
db.orders.find( { qty: { $gt: 10 } , status: "A" } )
交叉索引和复合索引
交叉索引不会消除对创建复合索引的需要。因为索引中字段的列举顺序和排序顺序(升序或降序)在复合索引中都很重要。一个复合索引可能不支持对于不包含索引前缀字段或指定了不同的排序顺序的查询条件。
例如,一个 orders
集合有如下复合索引,status
在 ord_date
之前:
{ status: 1, ord_date: -1 }
这个复合索引可以支持以下查询:
db.orders.find( { status: { $in: ["A", "P" ] } } )
db.orders.find(
{
ord_date: { $gt: new Date("2014-02-01") },
status: {$in:[ "P", "A" ] }
}
)
但不支持以下查询:
db.orders.find( { ord_date: { $gt: new Date("2014-02-01") } } )
db.orders.find( { } ).sort( { ord_date: 1 } )
但是,如果这个集合有以下两个单独的索引:
{ status: 1 }
{ ord_date: -1 }
那么,这两个索引可以或者分别或者通过交叉索引,支持前面提到的(aforementioned)四个查询。
是选择创建复合索引支持你的查询还是用交叉索引,依赖于你的系统的具体细节。
交叉索引和排序
当 sort()
操作要求的一个完整的索引与查询谓语命中的索引完全分离时,交叉索引不会被应用。
例如,集合 orders
上有以下索引:
{ qty: 1 }
{ status: 1, ord_date: -1 }
{ status: 1 }
{ ord_date: -1 }
MongoDB 不能用交叉索引满足以下查询:
db.orders.find( { qty: { $gt: 10 } } ).sort( { status: 1 } )
就是说,MongoDB 不能用 { qty: 1 }
索引来查询,同时,用完全分离的 { status: 1 }
索引或 { status: 1, ord_date: -1 }
索引来排序。
然而,以下查询中,由于 { status: 1, ord_date: -1 }
可以满足部分查询谓语,所以 MongoDB 可以使用交叉索引:
db.orders.find( { qty: { $gt: 10 } , status: "A" } ).sort( { ord_date: -1 } )
总结
(暂无)
猜想
- 我们系统中每个索引上都带
accountId: 1
前缀,那么两个索引有相同的前缀时是不是也可以用到交叉索引?
实验与补充
(待续)
网友评论