让我们以
_id
这个领域为例,它在整个系列中是独一无二的。
使用
_id
为前缀的复合索引是否有意义,例如:
{
_id: 1,
A: 1
}
上面的索引是否比简单的索引更有效:
{
_id: 1
}
如果是这样,您能否给出一个查询示例?
我不同意评论,并说答案是:当然,在非常具体的情况下它是有意义的。我想到的最值得注意的一个是您是否希望索引覆盖查询,我们将在下面探讨。
在此答案中,考虑具有以下索引的集合
foo
:
> db.foo.getIndices()
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { u: 1 }, name: 'u_1', unique: true },
{ v: 2, key: { u: 1, A: 1 }, name: 'u_1_A_1' }
]
以及以下查询:
.find({u:123},{A:1, _id:0})
使用单字段
unique
索引会产生以下计划:
> db.foo.find({u:123},{A:1, _id:0}).hint({u:1}).explain().queryPlanner.winningPlan
{
stage: 'PROJECTION_SIMPLE',
transformBy: { A: 1, _id: 0 },
inputStage: {
stage: 'FETCH',
inputStage: {
stage: 'IXSCAN',
keyPattern: { u: 1 },
indexName: 'u_1',
...
indexBounds: { u: [ '[123, 123]' ] }
}
}
}
但是,使用复合索引会显示出不同的结果:
> db.foo.find({u:123},{A:1, _id:0}).hint({u:1, A:1}).explain().queryPlanner.winningPlan
{
stage: 'PROJECTION_COVERED',
transformBy: { A: 1, _id: 0 },
inputStage: {
stage: 'IXSCAN',
keyPattern: { u: 1, A: 1 },
indexName: 'u_1_A_1',
...
indexBounds: { u: [ '[123, 123]' ], A: [ '[MinKey, MaxKey]' ] }
}
}
此处显着的区别是使用复合索引时缺少
FETCH
阶段。顺便说一句,复合索引是我测试中数据库自然选择的索引(6.0
)。
以相关方式,如果查询要在
A
字段上包含查询谓词,则复合索引可以检查该条件,而单字段索引则不能。通过唯一字段上的相等条件,使用单字段索引带来的 FETCH
的缺点得到了限制(只能检索和不必要地丢弃单个文档)。
所以,是的,在某些情况下,以唯一字段为前缀的复合索引可以提供一些价值。也就是说,索引通常是为了找到整体工作负载的适当平衡。因此,复合索引可以为一个或两个特定查询提供的微观优化可能不值得强制数据库维护一个全新的索引。
在这个答案中,我使用了
u
字段,而不是最初问题中提出的 _id
。这是因为,在撰写本文时,MongoDB 对 _id
字段进行了一些特殊处理。因此,概括并使用不同的字段/索引(unique
)可以更轻松地进行演示和推理。