MongoDB带Limit查询执行计划:如何让PROJECTION_SIMPLE先于SORT执行?
MongoDB查询中强制投影在排序前执行的问题
执行带limit子句的MongoDB查询时,发现executionStats中的totalDataSizeSorted为71561167KB;移除limit子句后,该值仅为25624890KB,且返回的记录数更多。
带limit的查询语句:
db.mycollection.find({ $and: [ { state: "Active" }, { expires_date: { $gte: new Date(1451586600000), $lte: new Date(1666003832377) } }, { $or: [ { last_checked: { $lte: new Date(1666003832377) } }, { last_checked: { $exists: false } } ] }, { $or: [ { processingState: { $exists: true } } ] } ] }, {_id:1,last_checked:1 }) .sort({last_checked:1}) .limit(10000) .explain("executionStats");
执行计划显示:带limit的查询中PROJECTION_SIMPLE阶段在SORT阶段之后执行;而无limit的查询里,投影操作先于排序执行,因此排序的数据量更小。
强制投影在排序前执行的方法
1. 使用聚合管道替代find查询
聚合管道的执行阶段是严格按顺序执行的,只要把$project放在$sort之前,就能确保先完成投影再排序。示例代码:
db.mycollection.aggregate([ { $match: { state: "Active", expires_date: { $gte: new Date(1451586600000), $lte: new Date(1666003832377) }, $or: [ { last_checked: { $lte: new Date(1666003832377) } }, { last_checked: { $exists: false } } ], processingState: { $exists: true } } }, { $project: { _id: 1, last_checked: 1 } }, { $sort: { last_checked: 1 } }, { $limit: 10000 } ]).explain("executionStats")
2. 创建覆盖索引
如果能创建包含查询过滤字段、排序字段以及投影字段的覆盖索引,MongoDB会直接从索引中读取所需数据,无需加载全文档,自然也能减少排序的数据量。示例索引创建语句:
db.mycollection.createIndex( { state: 1, expires_date: 1, last_checked: 1, processingState: 1 }, { partialFilterExpression: { processingState: { $exists: true } } } )
注意:partialFilterExpression需要MongoDB 3.2及以上版本支持,且该索引需匹配你的查询过滤条件才能生效。
内容的提问来源于stack exchange,提问作者Ajay Verma
相关产品推荐
相关产品推荐

