MongoDB: $in in in aggregation is slow despite the index
MongoDB: $in in aggregation is slow despite the index
我有一组用户(~8k 文档)和一组作业(~150k 文档)。我需要创建一个聚合,其中包含一个阶段,用于查找每个用户被接受的工作(在工作模型中接受的是一个 ObjectId 数组):
db.getCollection('users')
.aggregate([
{
$lookup: {
from: 'jobs',
as: 'jobs',
let: { accepted: '$_id' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $gte: ['$timestamp', 1643223600] },
{ $in: ['$$accepted', '$accepted'] }
]
}
},
},
]
}
},
])
这个聚合速度非常慢。即使将输出记录的数量限制为 10 个,也需要大约 1 分钟的时间才能完成。虽然,时间戳大于 1643223600 的作业数量并不是很大——大约有 3000 个文档。我添加了以下索引:
{timestamp: -1},
{accepted: 1}
但这并没有帮助。但是,如果我创建数据库的副本并删除所有不满足时间戳条件的班次,则聚合工作得更快(几秒钟)。这是否意味着该索引由于某种原因不起作用?如果 运行 对作业集合进行简单查询,并在接受字段上进行条件解释,则表明已执行 IXSCAN
UPD:由于 $in 不适用于复合索引,Mongodb4.4 的解决方法是:
{
$lookup: {
from: 'jobs',
as: 'jobs',
localField: '_id',
foreignField: 'accepted'
}
},
{ $match: { $expr: { $ne: [{ $size: '$jobs' }, 0] } } },
{ $unwind: '$jobs' },
{
$match: { 'jobs.timestamp': { $gte: 1643223600 } }
},
查询
(需要 MongoDB 5)
users.aggregate(
[{"$lookup":
{"from":"jobs",
"localField":"_id",
"foreignField":"accepted",
"pipeline":[{"$match":{"timestamp":{"$gte":1643223600}}}],
"as":"jobs"}}])
在 accepted
上创建多键索引后尝试此操作,如果需要,也在 timestamp
上尝试此操作。
聚合 $in
即使在 Mongodb 5 中也不能使用索引,所以它没有被使用。
请参阅 here 关于 $expr
和索引的使用。
我有一组用户(~8k 文档)和一组作业(~150k 文档)。我需要创建一个聚合,其中包含一个阶段,用于查找每个用户被接受的工作(在工作模型中接受的是一个 ObjectId 数组):
db.getCollection('users')
.aggregate([
{
$lookup: {
from: 'jobs',
as: 'jobs',
let: { accepted: '$_id' },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $gte: ['$timestamp', 1643223600] },
{ $in: ['$$accepted', '$accepted'] }
]
}
},
},
]
}
},
])
这个聚合速度非常慢。即使将输出记录的数量限制为 10 个,也需要大约 1 分钟的时间才能完成。虽然,时间戳大于 1643223600 的作业数量并不是很大——大约有 3000 个文档。我添加了以下索引:
{timestamp: -1},
{accepted: 1}
但这并没有帮助。但是,如果我创建数据库的副本并删除所有不满足时间戳条件的班次,则聚合工作得更快(几秒钟)。这是否意味着该索引由于某种原因不起作用?如果 运行 对作业集合进行简单查询,并在接受字段上进行条件解释,则表明已执行 IXSCAN
UPD:由于 $in 不适用于复合索引,Mongodb4.4 的解决方法是:
{
$lookup: {
from: 'jobs',
as: 'jobs',
localField: '_id',
foreignField: 'accepted'
}
},
{ $match: { $expr: { $ne: [{ $size: '$jobs' }, 0] } } },
{ $unwind: '$jobs' },
{
$match: { 'jobs.timestamp': { $gte: 1643223600 } }
},
查询
(需要 MongoDB 5)
users.aggregate(
[{"$lookup":
{"from":"jobs",
"localField":"_id",
"foreignField":"accepted",
"pipeline":[{"$match":{"timestamp":{"$gte":1643223600}}}],
"as":"jobs"}}])
在 accepted
上创建多键索引后尝试此操作,如果需要,也在 timestamp
上尝试此操作。
聚合 $in
即使在 Mongodb 5 中也不能使用索引,所以它没有被使用。
请参阅 here 关于 $expr
和索引的使用。