本文将会介绍 MongoDB 复合索引的概念,以及如何创建复合索引。
复合索引
复合索引(compound index)是指基于多个字段的索引,通常可以用于优化匹配多个字段的查询。
复合索引同样可以使用 createIndex() 方法创建,语法如下:
db.collection.createIndex({
field1: type,
field2: type,
field3: type,
...
});
其中,field1、field2、field3 都是字段;type 代表了类型,1 表示索引中的数据按照升序排列,-1 表示按照降序排列。
ℹ️MongoDB 复合索引最多包含 32 个字段。
复合索引中的字段顺序至关重要。如果一个复合索引包含字段 field1、field2,索引首先按照 field1 进行排序,如果 field1 相同,再按照 field2 排序。
复合索引遵循最左匹配原则。例如,一个复合索引包含字段 field1、field2,可以支持以下查询优化:
- 基于字段 field1 的匹配
- 基于字段 field1 以及 field2 的匹配
但是,它不支持基于字段 field2 的查询优化。
优化示例
首先,我们为集合 movies 创建一个基于 Title 以及 Release Date 的复合索引:
db.movies.createIndex({
Title: 1, 'Release Date': 1 })
'Title_1_Release Date_1'
然后查找名称包含 batman,并且在 2005 年 1 月 15 日发行的电影:
db.movies.find({
Title: /batman/i, "Release Date": 'Jun 15 2005'}).explain('executionStats');
...
inputStage: {
stage: 'IXSCAN',
filter: {
Title: BSONRegExp("batman", "i")
},
nReturned: 1,
executionTimeMillisEstimate: 5,
works: 3180,
advanced: 1,
needTime: 3178,
needYield: 0,
saveState: 3,
restoreState: 3,
isEOF: 1,
keyPattern: {
Title: 1,
'Release Date': 1
},
indexName: 'Title_1_Release Date_1',
...
查询使用了索引 Title_1_Release Date_1,而不是扫描整个集合。
然后查找名称包含 batman 的电影:
db.movies.find({
Title: /batman/i}).explain('executionStats');
...
inputStage: {
stage: 'IXSCAN',
filter: {
Title: BSONRegExp("batman", "i")
},
nReturned: 6,
executionTimeMillisEstimate: 0,
works: 3192,
advanced: 6,
needTime: 3185,
needYield: 0,
saveState: 3,
restoreState: 3,
isEOF: 1,
keyPattern: {
Title: 1,
'Release Date': 1
},
indexName: 'Title_1_Release Date_1',
...
以上查询只匹配了 Title,优化器仍然能够使用复合索引进行优化。
然后查找在 2005 年 1 月 15 日发行的电影:
db.movies.find({
"Release Date": 'Jun 15 2005'}).explain('executionStats');
...
executionStages: {
stage: 'COLLSCAN',
filter: {
'Release Date': {
'$eq': 'Jun 15 2005'
}
},
nReturned: 1,
...
这种情况下,查询优化器无法使用复合索引,而是通过扫描整个集合(COLLSCAN)查找数据。