使用“in”和两个索引之间的数组进行查询时有啥区别?

Posted

技术标签:

【中文标题】使用“in”和两个索引之间的数组进行查询时有啥区别?【英文标题】:What's the difference when query using `in` and an array between two indexes?使用“in”和两个索引之间的数组进行查询时有什么区别? 【发布时间】:2019-05-15 04:26:01 【问题描述】:

MongoDB 中包含如下文档的集合:

a: 1, b: 1
a: 2, B: 2
a: 3, B: 3
a: 3, B: 2
a: 2, B: 1

带有 uniq 索引 a_1_b_1b_1_a_1

查询:a: x, b: $in: [....]

哪个索引更好?还是一样?

查询匹配数组如何工作?


更新: shard key 是否影响查询索引? 分片键:a_1_c_1 额外索引:b_1_a_1 查询:a: x, b: y

    通过分片键a_1_c_1中的a=x路由到分片,然后使用索引b_1_a_1在分片中查询 通过分片键路由和查询必须使用分片键?

【问题讨论】:

【参考方案1】:

来自 compound indexes 上的 MongoDB 手册部分:

db.products.createIndex( "item": 1, "stock": 1 )

复合索引中列出的字段的顺序很重要。该索引将包含对文档的引用,这些文档首先按 item 字段的值排序,然后在 item 字段的每个值中,按 stock 字段的值排序。

鉴于上述情况,我们可以看到a_1_b_1 将首先由a 分段,然后由b 分段,而b_1_a_1 将首先由b 分段,然后由a 分段。

现在让我们检查您的查询:a: x, b: $in: [....] 请注意,此查询匹配特定的a 值和一系列可能的b 值。在索引a_1_b_1 中,索引扫描将仅限于匹配的a 块,并且将在其中搜索所有b 值;但是,如果您使用索引b_1_a_1,则索引扫描必须在不同的b 块之间“跳转”并在每个块中搜索匹配的a 值。

访问“靠近”在一起的数据通常效率更高,因此您需要选择匹配文档更有可能位于其中的索引。在这种情况下,将所有文档放在同一个 a 块中可能是一个更好的选择,因为发生的“跳跃”应该更少,因此您应该使用索引 a_1_b_1

然而,这过于简单化了。实际的性能影响可能可以忽略不计,尤其是在ab 的可能范围非常小的情况下。

您还应该考虑一个额外的因素:查询前缀。如果您发现自己有时只使用a 值执行查询,那么您应该选择索引a_1_b_1。同样,如果您有时只使用b 值执行查询,那么您可能应该选择b_1_a_1

这是因为如果您的查询不完全匹配索引但匹配该索引的前缀,则该索引仍然适用。因此,在索引a_1_b_1 中,您可以对a: x, b: $in: [....]a: x 执行高效查询,但您无法对b: $in: [....] 执行高效查询。

最后,通常还可以利用index intersection 来拥有两个独立的索引a_1b_1,从而在性能和灵活性之间取得平衡。


考虑到以上所有因素,我不建议您过多关注索引性能,直到您的数据大小开始需要它。毕竟,您可以根据需要删除旧索引并构建新索引。使用目前有效的方法,随着时间的推移监控性能,并在看起来可能超出当前使用的情况时重新评估。

【讨论】:

感谢您的解释,集合中有数十亿个文档,ab 都有很大的范围。还有一个问题是:如果集合按索引b_1_a_1 分片,查询a:x, b: $in: [..] 是否会作为b: x, a: y 的倍数执行? @nFeng 不幸的是,我对分片集合没有任何经验,对它们的工作原理只有粗略的了解,所以我没有答案。

以上是关于使用“in”和两个索引之间的数组进行查询时有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

list和vector有啥区别

.NET Core 中的 SDK 和运行时有啥区别?

在 numpy 中,用空元组和省略号对数组进行索引有啥作用?

SQL中 exists和in的区别是啥啊?

Python中列表和字典有啥区别,分别适用于啥

Google Colab 中的本地运行时和托管运行时有啥区别?