在PostgreSQL中拥有许多序列是否有问题?

8

我正在使用Postgres中的虚拟私有数据库模式开发应用程序。

因此,每个用户都会获得他的id,并且该用户的所有行都将持有此id以与其他用户分离。该id还应成为主键的一部分。此外,每行必须具有在用户范围内唯一的id。这个id将成为主键的另一部分。 如果我们需要跨多个服务器扩展此功能,还可以附加第三列到标识生成此id的碎片的pk中。

我的问题是如何创建每个用户唯一的id。我提出了一些选项,但不确定所有影响。对我来说,最有前途的两个解决方案是:

为每个用户创建一个序列:

可以使用触发器自动完成每次创建用户时的操作。这肯定是事务安全的,而且在性能方面应该也相当不错。 我担心的是,这要处理大量用户(100k +),我不知道Postgres如何处理100k+序列。我试图找出序列的实现方式,但没有成功。

在用户表中使用计数器:

将所有用户保存在一个表中,并保留一个字段,其中包含为该用户提供的最新id。 当用户开始事务时,我可以锁定用户表中的行,并使用用户表中的最新id作为起始值创建一个临时序列。然后可以使用该序列为新条目提供id。 在退出事务之前,必须将当前值写回用户表,并释放锁定。如果同一用户的另一个事务尝试并发插入行,则会停止,直到第一个事务释放对用户表的锁定。 这样,我就不需要成千上万个序列,而且我认为不同用户之间的并发访问不会经常发生(应用程序具有OLTP特性-因此不会有长时间的事务),即使发生这种情况,它也只会停留约一秒钟,不会造成任何伤害。

我的另一个问题是,是否应该只使用2列(或者如果shard_id加入游戏,则使用三列),并将它们组合成复合主键,还是将它们放在一列中。我认为将它们放在单独的列中处理会更容易,但性能如何?假设两个值都是32位整数-在索引中是否有2个int列或1个bigint列更好?

谢谢所有答案, Alex


1
有趣的设计。你考虑过只使用一个序列并共享吗?我从来不太喜欢复合键,所以对于你问题的第二部分,我的答案将是bigint。对于第一部分,我建议为所有用户使用单个序列。唯一的问题是序列中会存在间隔。然而,我相信你有理由让所有用户的序列重叠。 - Greg
在以前的项目中,我分享了序列 - 在这种情况下,因为有2个原因,我正在考虑不共享它:首先,这个主键被同一表和其他表中的许多行引用 - 共享的id必须是bigint才能在所有用户中保持唯一。如果只需要在一个用户中保持唯一,则smallint就足够了。为了使这些数据集的访问更快,我希望在所有引用数据集中也有user_id。第二个原因是id成为url的一部分 - 有较短的数字可以使url模式更易于人类阅读。 - user3347114
恶魔的辩护:你有考虑过其他多租户架构吗? - Mike Sherrill 'Cat Recall'
1个回答

8
我认为序列不适用于您想要的规模(100k个序列)。序列被实现为只有一个行的关系。每个序列都将出现在系统目录中(pg_class),其中还包含所有表、视图等。在那里拥有100k行肯定会严重拖慢系统速度。持有与这些序列关系相关的所有数据结构所需的内存量也会很大。
如果与临时序列相结合,您的第二个想法可能更实用,也更具可扩展性。
对于您的第二个问题,我认为复合键不会比单列键更糟糕,因此我会选择符合您功能需求的任何一种。

谢谢你的回答 - 基本上我已经猜到了。你知道关于Postgres中序列的更多文献吗? - user3347114
@user3347114 不是很清楚。我查看了源代码以了解它们的工作原理。请参见http://doxygen.postgresql.org/sequence_8c_source.html - harmic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接