mongodb - MongoDB 部分索引无法按预期使用计数
问题描述
在mongoDB 3.6.3上,我用两百万条记录创建了这个集合:
function randInt(n) { return parseInt(Math.random()*n); }
for(var j=0; j<20; j++) {
print("Building op "+j);
var bulkop=db.media.initializeOrderedBulkOp() ;
for (var i = 0; i < 100000; ++i) {
bulkop.insert(
{
id_profile: NumberLong("222"),
needle_id: NumberInt(randInt(2000000000)),
visibility: NumberInt(randInt(5)),
}
)
};
print("Executing op "+j);
bulkop.execute();
}
然后我创建这个部分索引:
db.media.createIndex(
{"id_profile": 1, "visibility": 1},
{unique: false, partialFilterExpression: { "needle_id": { $exists: true } }}
);
然后我运行这个与部分索引完全匹配的查询:
db.media.count({$and:[
{id_profile:NumberInt(222)},
{visibility:NumberInt(0)},
{needle_id:{$exists:true}}]})
但它很慢:(事实上,它的速度就像我没有使用部分索引一样,我需要过滤所有没有needle_id的文档:
db.media.createIndex(
{"id_profile": 1, "visibility": 1},
{unique: false}
);
db.media.count({$and:[
{id_profile:NumberInt(222)},
{visibility:NumberInt(0)},
{needle_id:{$exists:true}}]})
那么它是部分索引的错误吗?我能做些什么来加快我的计数?
解决方案
我调查这个问题已经有一段时间了,似乎对部分索引运行计数查询并不能避免遍历索引的所有文档。
在大型集合上创建索引时,运行基于索引的计数查询会在几毫秒内完成。它实际上是在计算所提供值的索引大小。
在查看此类查询的执行计划时,我们可以单独注意到“IDX_SCAN”阶段,它代表索引扫描。(扫描请求边界上的索引并计算它包含的文档数)
但是当使用部分索引时,mongo 实现的计数功能似乎不是在进行索引扫描,而是在文档上运行,就像我们运行修改查询一样。然后最终返回文档的总数。
这可以通过查看此类查询的执行计划来证明,并看到它显示阶段是“FETCH”,而不是“IDX_SCAN”,而是使用索引获取,所以如果索引不是在全部。
更完整的信息可以在这里找到:为什么“distinct”和“count”命令在 MongoDB 中的索引项上发生如此缓慢?
推荐阅读
- c# - 在c#的电报中删除加入和留言
- javascript - 不使用标准 DOM 元素选择方法在 DOM 中查找对象
- gridsome - 使用源文件系统插件时是否可以在 gridsome 中使用嵌套文件夹?
- flutter - Flutter Getx - 未找到“Xxx”。您需要调用“Get.put(Xxx())” - 但我已调用 Get.put(Xxx())
- python - 如何从 pmdarima.auto_arima 中提取估计(无预测)值
- java - 使用 spring boot 使用 api
- rust - 是否可以在宏中将变量作为标识符传递?
- sql - 查看完成的专栏
- symfony - 无法覆盖 symfony 5 异常模板
- html - 角落有边框的图像 - img 下方的空间