MongoDB多值$in计数查询性能异常问题问询
分析与解决MongoDB多值$in计数查询性能问题
问题梳理
你遇到的情况挺典型的:你的my_collection有1644662条记录,给document_type_id建了索引,单值$in的计数查询(比如查["7"]或["3"])都很快,耗时分别是0.285秒和0.365秒,但把两个值组合成$in: ["3", "7"]时,居然耗时长达54秒,这明显不对劲。
执行计划关键问题分析
从你贴的执行计划里能找到核心原因:
- 索引扫描(
IXSCAN)阶段只花了2729毫秒,这部分是正常的,它快速找到了所有匹配3和7的索引条目(总共1573238条)。 - 但接下来的
FETCH阶段耗时高达73253毫秒,而且totalDocsExamined等于totalKeysExamined——这意味着MongoDB把所有匹配索引的文档都从磁盘(或内存)中读取出来了,然后才进行计数。 - 对比单值查询的情况:单值时MongoDB可以直接利用索引完成计数(也就是「索引覆盖查询」),根本不需要读取实际文档,所以速度飞快。但多值
$in时,3.4版本的查询优化器没选择这种高效路径,反而走了先读文档再计数的流程。
解决方案
针对这个问题,给你几个可行的解决办法:
1. 改用countDocuments()替代count()
MongoDB的count()方法在新版本中已经被标记为弃用,而countDocuments()的查询优化逻辑更完善,能更好地处理多值$in的计数场景,大概率会直接利用索引完成统计,避免FETCH操作。执行命令如下:
db.getCollection('my_collection').countDocuments({"document_type_id": {"$in": ["3", "7"]}})
2. 使用聚合管道实现计数
如果countDocuments()还是没达到预期效果,可以试试用聚合管道。$match阶段会利用索引过滤数据,$count阶段直接统计匹配结果,同样不需要读取完整文档:
db.my_collection.aggregate([ { $match: { document_type_id: { $in: ["3", "7"] } } }, { $count: "total_records" } ])
3. 考虑升级MongoDB版本
你当前用的是MongoDB 3.4.9,这个版本比较老旧了。后续的版本(比如4.0及以上)对查询优化器做了很多改进,针对多值$in的计数场景,会默认选择索引覆盖的路径,从根源上解决这类性能问题。
内容的提问来源于stack exchange,提问作者fazalerabbi
相关产品推荐
相关产品推荐

