我的主表 ,Users
存储有关用户的信息。我计划有一个UserId
字段作为表的主键。我可以完全控制这些键的创建和分配,并且我想确保我以提供良好性能的方式分配键。我应该怎么办?
1 回答
你有几个选择:
- 最通用的解决方案是使用RFC 4122中指定的 UUID 。
例如,您可以有一个STRING(36)
存储 UUID 的。或者您可以将 UUID 存储为一对INT64
s 或一个BYTE(16)
. 使用 UUID 存在一些陷阱,因此请阅读此答案的详细信息。
如果您想节省一点空间并且绝对确定您将拥有少于几十亿的用户,那么您可以使用 INT64,然后使用随机数生成器分配 UserId。你想确保你的用户少于几十亿的原因是因为生日问题,一旦你有 4B 用户,你得到至少一次碰撞的几率大约是 50%,并且从那里开始增长非常快。如果您分配一个已经分配给前一个用户的 UserId,那么您的插入事务将失败,因此您需要为此做好准备(通过在生成新的随机数后重试事务)。
如果用户表中有一些列 ,
MyColumn
您希望将其用作主键(可能是因为您知道您会经常使用该列查找条目),但您不确定该列的趋势导致热点(例如,因为它是按顺序生成或基于时间戳生成的),那么您还有另外两个选择:
3a)您可以“加密”MyColumn
并将其用作您的主密钥。用数学术语来说,您可以对键值使用自同构,这会产生混乱地打乱它们的效果,同时仍然不会多次分配相同的值。在这种情况下,您不需要存储MyColumn
完全分开,而是您只会存储/使用加密版本,并在必要时在您的应用程序代码中对其进行解密。请注意,这种加密不需要是安全的,而是只需要保证原始值的位以可逆的方式充分加扰。例如:如果您的 MyColumn 值是按顺序分配的整数,您可以只反转 MyColumn 的位以创建一个充分加扰的主键。如果您有更有趣的用例,您可以使用像XTEA这样的加密算法。
3b) 有一个复合主键,其中第一部分是 a ShardId
,计算为hash(MyColumn) % numShards
,第二部分是MyColumn
。散列函数将确保您不会通过将行分配给单个拆分来创建热点。可以在此处找到有关此方法的更多信息。请注意,您不需要使用加密哈希,尽管 md5 或 sha512 是很好的函数。SpookyHash也是一个不错的选择。选择正确数量的分片是一个有趣的问题,并且可能取决于实例中的节点数量;它实际上是热点避免能力(更多分片)和读取/扫描效率(更少分片)之间的权衡。如果您只有 3 个节点,那么 8 个分片可能就可以了。如果你有 100 个节点;那么 32 分片是一个合理的尝试值。