MongoDb - 用于分片目的的重复索引字段?

Posted

技术标签:

【中文标题】MongoDb - 用于分片目的的重复索引字段?【英文标题】:MongoDb - Duplicate index fields for sharding purposes? 【发布时间】:2020-11-23 00:33:25 【问题描述】:

我想建立一个集群来存储日志数据。每个文档都有几个字段,但这些是关键字段:

user_id(中等基数) 标识符(它具有极高的基数,但不能保证在用户之间是唯一的,例如它可以是 UPC) 频道(低基数) 时间戳

该集合预计将包含超过 10 亿个文档,因此分片和性能在这里很重要。

现在几乎所有对集合的高频查询都将包含user_id,因为日志在 UI 中以唯一方式显示给每个用户。大多数查询将在user_id + identifier 上进行。一些查询将有时间限制。一些查询也使用channel,但不是全部。 user_id 是一个单调递增的字段。

我想在hashed(user_id) 上进行分片。一个理想的索引是"user_id": 1, "identifier": 1, "timestamp": 1,所以我做到了。我尝试在hashed(user_id) 上进行分片,但在这种情况下它不起作用,我意识到user_id 必须属于同一类型。但是,创建"user_id": "hashed", "identifier": 1, "timestamp": 1 的索引也是不可能的,因为不允许使用带有散列的复合键。

我最好的选择是什么?

只用hashed(user_id) 创建一个索引,这样我就可以对它进行分片,然后用"user_id": 1, "identifier": 1, "timestamp": 1 创建另一个索引?我会在这里招致存储损失。 不要散列user_id,即使它是单调递增的,而是在"user_id": 1, "identifier": 1上分片?我不确定与在hashed(user_id) 上进行简单分片相比是否有缺点 其他选项?

【问题讨论】:

【参考方案1】:

请注意,MongoDB 4.4 允许使用单个散列字段的复合索引:https://docs.mongodb.com/manual/core/hashed-sharding/

如果您不能轻松升级到 4.4,考虑到这里的存储压力很大,文档数量很大,并且大多数查询将同时包含 user_ididentifier,那么在 "user_id": 1, "identifier": 1 上进行分片听起来是最好的你在这里有选择。它将允许这些查询更快,而牺牲您需要搜索每个用户的所有标识符或基于时间的查询的其他查询。

我不确定在低于 MongoDB 4.4 的版本上是否有更好的解决方案。

【讨论】:

这是个好时机,似乎 4.4 版完美地解决了我的用例问题——谢谢!【参考方案2】:

只用 hashed(user_id) 创建一个索引,这样我就可以对其进行分片 然后是另一个索引 "user_id": 1, "identifier": 1, "timestamp": 1?我会在这里受到存储损失。

你只能有一个分片键(这需要是一个索引、单个或复合字段)。对于分片键的哈希索引字段,从 MongoDB v4.2 开始,它只能是单个字段索引。

使用分片键(或复合分片键的前缀)使用条件查询分片集合将是有针对性的查询。 mongos 将仅访问所需的分片。因此,这将是一个有效的查询。

不使用分片键作为查询条件的一部分进行查询只会导致分散-收集操作 - 将访问集群中的所有分片。甚至,如果查询的字段上有索引,仍然会进行分散操作。

因此,选择分片键可能是分片集群设置中最重要的部分。

见Targeted Operations vs. Broadcast Operations。

即使 user_id 单调递增,也不要散列 而是在 "user_id": 1, "identifier": 1 上分片?我不确定是否 与简单的分片相比,这里有一些缺点 散列(user_id)

您的查询需求应该推动您选择分片键(我已经在上面提到过分片键)。

MongoDB v4.4(最新)允许Hashed Sharding on a Compound Hashed Index。

【讨论】:

以上是关于MongoDb - 用于分片目的的重复索引字段?的主要内容,如果未能解决你的问题,请参考以下文章

mongodb 索引唯一性约束

MongoDB - _id 索引大小的奇怪差异

MogoDB 分片键

我可以在 Firestore 中重复使用现有字段作为分片时间戳吗?

MongoDb在并非所有文档中的字段上创建唯一索引[重复]

mongodb基本操作