mongodb - 未使用MongoDB复合索引
问题描述
我有一个包含近 100k 个文档的 mongodb 索引。在每个文档上,有以下 3 个字段。
arrayX:[ObjectId] someID:ObjectId 时间戳:日期
我按该顺序为 3 个字段创建了复合索引。
当我尝试然后触发聚合查询(用伪代码写在下面)时,如
match(
and(
arrayX: (elematch: A),
someId: Y
)
)
sort (timestamp: 1)
它最终不会使用复合索引。
我知道的方式是,当我使用时.explain()
,winningPlan 阶段是FETCH
,inputStage
isIXSCAN
和indexname
is timestamp_1
,这意味着它只使用我为时间戳字段创建的另一个单键索引。
有趣的是,如果我删除排序阶段,并保持一切完全相同,mongodb 最终会使用复合索引。
是什么赋予了?
解决方案
多键索引对排序没有用处。我希望使用其他索引的计划列在拒绝计划中。
如果您使用 allPlansExecution 选项运行说明,则响应还将显示每个计划的执行时间等。
由于多键索引不能用于对结果进行排序,因此该计划将需要阻塞排序阶段。这意味着必须检索所有匹配的文档,然后在发送响应之前在内存中进行排序。
另一方面,使用 timestamp_1 索引意味着在遍历索引时会以预先排序的顺序遇到文档。这里的权衡是没有阻塞排序阶段,但必须检查每个文档以查看它是否与查询匹配。
对于不是很大的数据集,或者当查询将匹配集合的很大一部分时,没有阻塞排序的计划将更快地返回结果。
您可以测试创建另一个索引,{ someID:1, timestamp:1 }
因为这可能会减少扫描的文档数量,同时仍然避免阻塞排序。
删除排序阶段时选择复合索引的原因是该阶段可能占执行时间的大部分。
解释输出的 executionStats 部分中的字段在解释结果中进行了解释。比较每个阶段的估计执行时间可以帮助您确定可以调整查询的位置。
推荐阅读
- labview - 如何设置簇数组的tab顺序,簇元素在LabVIEW中具有不同的数据类型?
- python - 在具有给定位置坐标的节点图中设置边标签的问题
- c# - 通过 nvidia quadro 600 gpu 模式访问时 C# DOT NET 应用程序崩溃 - nvd3dum.dll 崩溃
- php - 如何从PHP中的文本中提取名称
- c++ - 如何让我的编译器更愚蠢(错误的索引)?
- html - sed 命令处理输入流并用标签替换所有HTML标签
- angular - selectionChange 不会为 mat-select 中的默认选项发出 - Angular Material
- aframe - 依赖于具有多个 true 的组件的 Aframe 组件
- python - 为什么 Python 生成的 ELF 比原始源代码大?
- swift - 如何在 macOS 上的照片应用中访问照片