Mongodb 索引,partialfilters 是否也应包含在索引中?
Mongodb index, should partialfilters also be included in the index?
我有这样的查询:
collection.find({
type: "person",
image: {
$exists: true
}
}, {
sort: [
["age", -1]
],
limit: 9,
)
如果我已经过滤了这些字段,还需要将它们包含在索引中吗?
collection.createIndex(
{type: 1, image: 1, age: -1},
{
partialFilterExpression: {
type: 'person',
image: {
$exists: true
}
},
background: true
}
)
或者它是否已经通过部分过滤器表达式知道,而我只是通过未修复的内容进行查询?
collection.createIndex(
{age: -1},
{
partialFilterExpression: {
type: 'person',
image: {
$exists: true
}
},
background: true,
name: "ageIndex"
}
)
想一想,也许正确的做法是不索引所有字段,而是使用提示强制数据库使用索引?
collection.find({
type: "person",
image: {
$exists: true
}
}, {
sort: [
["age", -1]
],
limit: 9,
).hint("ageIndex")
这实际上会正确使用索引并忽略集合中的其他文档吗?
根据 MongoDB Partial Index documentation,如果在该表达式中执行查询,则如果字段已经在 partialFilterExpression 中,则无需将这些字段包含在索引中。
下面的索引将完美地用于提供的查询。
collection.createIndex(
{age: -1},
{partialFilterExpression: { type: 'person', image: { $exists: true }}}
)
查询:
collection.find({type: "person", image: { $exists: true }}, {sort: [["age", -1]])
连提示都不需要。
重要提示:如果类型不是'person',或者不提供图像过滤器——索引将不起作用。
如果查询结果 100% 在索引内,索引将仅起作用。
文档中的另一个示例:
索引:
db.restaurants.createIndex(
{ cuisine: 1, name: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
查询:
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
此查询不属于上述索引,因为它包含低于 5 的评分。
考虑正在查询的 示例文档 的集合,如问题:
{ _id: 1, type: "person", image: "i-1", age: 19, "fld": 12 },
{ _id: 2, type: "person", image: "i-2", age: 22, "fld": 121 },
{ _id: 3, type: "thing", image: "i-99", age: 29, "fld": 1212 }, // 'type' not 'person'
{ _id: 4, type: "person", age: 31, "fld": 12121 }, // 'image' missing
{ _id: 5, type: "person", image: "i-3", age: 13, "fld": 121212 },
{ _id: 6, type: "person", age: 43, "fld": 1212121 }, // 'image' missing
{ _id: 7, type: "person", image: "i-4", age: 20, "fld": 1 }
Do I need to include the fields in the index if I already have them
filtered? Or would it already know by the partial filter expression
and I'm only querying by what's not fixed?
创建一个索引:
db.collection.createIndex( { type: 1, age: -1 },
{
partialFilterExpression: {
type: 'person',
image: { $exists: true }
}
}
)
请注意,索引字段仅在 type
和 age
上。为什么?这在下面的索引使用验证中进行了解释。
查询:
db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } )
结果:
查询 returns 预期的筛选文档 和 的排序顺序。
{ "_id" : 2, "type" : "person", "image" : "i-2", "age" : 22, "fld" : 121 }
{ "_id" : 7, "type" : "person", "image" : "i-4", "age" : 20, "fld" : 1 }
{ "_id" : 1, "type" : "person", "image" : "i-1", "age" : 19, "fld" : 12 }
{ "_id" : 5, "type" : "person", "image" : "i-3", "age" : 13, "fld" : 121212 }
索引使用验证:
可以通过使用explain
方法生成查询计划来验证索引使用情况:
db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } ).explain()
计划输出显示过滤器 和 排序操作的索引使用情况。这在计划中被标记为 IXSCAN(索引扫描)和 SORT 阶段的缺失。这是此查询索引的正确用法。
在索引定义中,两个字段type
+ age
指定一个复合索引。这要求索引应用于 type
(用于过滤)和 age
(用于排序)。字段 image
无法在索引定义中指定,因为它 未与相等 条件一起使用(使用 $exists
);如果指定,索引将不会用于以下排序字段(来自 documentation):
An index can support sort operations on a non-prefix subset of the
index key pattern. To do so, the query must include equality
conditions on all the prefix keys that precede the sort keys.
查询计划(部分):
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.persons",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"type" : {
"$eq" : "person"
}
},
{
"image" : {
"$exists" : true
}
}
]
},
"queryHash" : "25E877F5",
"planCacheKey" : "C9D745BE",
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"image" : {
"$exists" : true
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"type" : 1,
"age" : -1
},
"indexName" : "type_1_age_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"type" : [ ],
"age" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : true,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"type" : [
"[\"person\", \"person\"]"
],
"age" : [
"[MaxKey, MinKey]"
]
}
}
}, ...
我有这样的查询:
collection.find({
type: "person",
image: {
$exists: true
}
}, {
sort: [
["age", -1]
],
limit: 9,
)
如果我已经过滤了这些字段,还需要将它们包含在索引中吗?
collection.createIndex(
{type: 1, image: 1, age: -1},
{
partialFilterExpression: {
type: 'person',
image: {
$exists: true
}
},
background: true
}
)
或者它是否已经通过部分过滤器表达式知道,而我只是通过未修复的内容进行查询?
collection.createIndex(
{age: -1},
{
partialFilterExpression: {
type: 'person',
image: {
$exists: true
}
},
background: true,
name: "ageIndex"
}
)
想一想,也许正确的做法是不索引所有字段,而是使用提示强制数据库使用索引?
collection.find({
type: "person",
image: {
$exists: true
}
}, {
sort: [
["age", -1]
],
limit: 9,
).hint("ageIndex")
这实际上会正确使用索引并忽略集合中的其他文档吗?
根据 MongoDB Partial Index documentation,如果在该表达式中执行查询,则如果字段已经在 partialFilterExpression 中,则无需将这些字段包含在索引中。
下面的索引将完美地用于提供的查询。
collection.createIndex(
{age: -1},
{partialFilterExpression: { type: 'person', image: { $exists: true }}}
)
查询:
collection.find({type: "person", image: { $exists: true }}, {sort: [["age", -1]])
连提示都不需要。
重要提示:如果类型不是'person',或者不提供图像过滤器——索引将不起作用。
如果查询结果 100% 在索引内,索引将仅起作用。
文档中的另一个示例:
索引:
db.restaurants.createIndex(
{ cuisine: 1, name: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
查询:
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
此查询不属于上述索引,因为它包含低于 5 的评分。
考虑正在查询的 示例文档 的集合,如问题:
{ _id: 1, type: "person", image: "i-1", age: 19, "fld": 12 },
{ _id: 2, type: "person", image: "i-2", age: 22, "fld": 121 },
{ _id: 3, type: "thing", image: "i-99", age: 29, "fld": 1212 }, // 'type' not 'person'
{ _id: 4, type: "person", age: 31, "fld": 12121 }, // 'image' missing
{ _id: 5, type: "person", image: "i-3", age: 13, "fld": 121212 },
{ _id: 6, type: "person", age: 43, "fld": 1212121 }, // 'image' missing
{ _id: 7, type: "person", image: "i-4", age: 20, "fld": 1 }
Do I need to include the fields in the index if I already have them filtered? Or would it already know by the partial filter expression and I'm only querying by what's not fixed?
创建一个索引:
db.collection.createIndex( { type: 1, age: -1 },
{
partialFilterExpression: {
type: 'person',
image: { $exists: true }
}
}
)
请注意,索引字段仅在 type
和 age
上。为什么?这在下面的索引使用验证中进行了解释。
查询:
db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } )
结果:
查询 returns 预期的筛选文档 和 的排序顺序。
{ "_id" : 2, "type" : "person", "image" : "i-2", "age" : 22, "fld" : 121 }
{ "_id" : 7, "type" : "person", "image" : "i-4", "age" : 20, "fld" : 1 }
{ "_id" : 1, "type" : "person", "image" : "i-1", "age" : 19, "fld" : 12 }
{ "_id" : 5, "type" : "person", "image" : "i-3", "age" : 13, "fld" : 121212 }
索引使用验证:
可以通过使用explain
方法生成查询计划来验证索引使用情况:
db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } ).explain()
计划输出显示过滤器 和 排序操作的索引使用情况。这在计划中被标记为 IXSCAN(索引扫描)和 SORT 阶段的缺失。这是此查询索引的正确用法。
在索引定义中,两个字段type
+ age
指定一个复合索引。这要求索引应用于 type
(用于过滤)和 age
(用于排序)。字段 image
无法在索引定义中指定,因为它 未与相等 条件一起使用(使用 $exists
);如果指定,索引将不会用于以下排序字段(来自 documentation):
An index can support sort operations on a non-prefix subset of the index key pattern. To do so, the query must include equality conditions on all the prefix keys that precede the sort keys.
查询计划(部分):
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.persons",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"type" : {
"$eq" : "person"
}
},
{
"image" : {
"$exists" : true
}
}
]
},
"queryHash" : "25E877F5",
"planCacheKey" : "C9D745BE",
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"image" : {
"$exists" : true
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"type" : 1,
"age" : -1
},
"indexName" : "type_1_age_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"type" : [ ],
"age" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : true,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"type" : [
"[\"person\", \"person\"]"
],
"age" : [
"[MaxKey, MinKey]"
]
}
}
}, ...