首页 > 解决方案 > 应该使用什么样的键来对同一个数据库表中的多行进行分组?

问题描述

用例

我需要存储分配给某个实体的文本。请务必注意,我始终只关心已分配给该实体的最新文本。如果插入新文本,甚至可能删除旧文本。而那个“可能”就是问题所在,因为我不能相信真的只有最新的文本可用。

我唯一不确定如何设计的是某些 INSERT 可以为某些实体提供 1 个或 N 个文本的情况。在后一种情况下,我需要知道哪些 N 文本属于为同一个实体完成的最新 INSERT。此外,插入 N 而不是 1 文本将非常罕见。

我知道可以使用两个不同的表来实现:一个计算一些主 ID,另一个将具有自己 ID 的单个文本映射到该主 ID。因为很少会出现多个文本,并且一个表格设计已经提供了可以轻松重复使用的列来将多个文本组合在一起,所以我更喜欢只使用一个。

此外,我还想到了哪个概念通常也会成为一个好的分组键。我有点怀疑其他人真的总是只实现两个表方法,因此创建了这个问题以获得更好的理解。当然,我可能只是错了,每个人都会不惜一切代价避免这种“黑客行为”。:-)

可能的键

事务本地时间戳

Postgres 使用current_timestamp支持事务本地时间戳的概念。当文本被存储时,我需要其中一个来存储,所以它们也可以用于分组?

虽然理论上存在冲突的可能性,但时间戳的分辨率为 1 微秒,这在实践中足以满足我的需求。文本是由人类用户上传的,多人同时为同一个实体上传文本的可能性很小。

该时间戳当然不会用作主键,仅在必要时对多个文本进行分组。

交易 ID

Postgres 支持txid_current来获取当前事务的 ID,它应该在当前安装的生命周期内不断增加。好消息是这个值总是可用的,应用程序不需要自己做任何事情。但是在恢复的情况下很容易损坏,不是吗?TXID 能否在恢复的集群中再次出现?

比我更了解事物的人会写以下内容:

不要将事务 ID 用于应用程序级别的任何内容。它是一个内部系统级字段。无论您尝试做什么,事务 ID 都可能不是正确的方法。

https://stackoverflow.com/a/32644144/2055163

您不应该将事务 ID 用于除事务标识符之外的任何内容。由于事务 ID 环绕,您甚至不能假设较低的事务 ID 是较旧的事务。

https://stackoverflow.com/a/20602796/2055163

我的分组不是想知道当前事务的 ID 的有效用例吗?

自定义序列

分组只需要每个事务的唯一键,这可以仅使用自定义序列来实现。我没有看到任何缺点,它的值消耗的存储空间比 UUID 少,并且可以很容易地被查询。

重用第一个唯一 ID

存储文本的表包含一个序列列,因此每个插入的文本都已经获得了一个单独的 ID。因此,第一个插入文本的 ID 总是可以简单地被额外重用作为所有以后添加的文本的组键。

在只插入一个文本的情况下,应该很容易使用currval,甚至不需要显式查询插入行的 ID。但是,如果有多个文本,这将不再起作用,因为currval它将提供更新的 ID,而不是仅提供每个事务的第一个 ID。所以需要一些特殊的处理。

APP生成的随机UUID

每个存储多个文本的请求都可以简单地生成一些 UUID 并按此分组。主要使用的数据库 Postgres 甚至支持相应的数据类型

我主要看到了它的缺点:它已经感觉非常hacky并且消耗了不必要的空间。OTOH,与要存储的文本相比,后者可能可以忽略不计。

标签: postgresqltransactions

解决方案


推荐阅读