我正在研究一个广泛使用UUID
s的数据库设计PRIMARY KEY
。然而,这让我面临一个非常重要的选择。如何命名这些列?我会称它们为uuid
,除了UUID
作为标识符,我必须在任何地方引用字段名称:
CREATE TABLE thingie (
"uuid" UUID PRIMARY KEY DEFAULT public.gen_random.uuid(),
foo VARCHAR,
bar VARCHAR,
);
一个直接的替代方法似乎是改为调用这些列id
:
CREATE TABLE thingie (
id UUID PRIMARY KEY DEFAULT public.gen_random.uuid(),
foo VARCHAR,
bar VARCHAR,
);
这样一来,我就没有列名,从语义上我可以争辩说 UUID 确实是一种 ID;在维恩图中,UUID 圆圈将完全放在 ID 圆圈中。
然而,我(我相信还有很多其他人)已经习惯于id
与自动递增INTEGER
列关联,以至于我害怕通过调用这些 ID 来打破某种潜规则id
。
如果你能用一些坚实的自行车脱落来消除我的困惑,我将非常感激。事实上,我的问题是:你会如何调用你的UUID
-typed 代理键,为什么?
除了代理键是每一行的唯一标识符这一事实之外,您不应将其赋予意义,因为从架构设计的角度来看,它采用何种格式并不重要。那时你应该关心的是它是一个标识某物的值,所以我坚持称它们为
ID
⁰。事实上,你拥有 UUID 的东西,除非你有一个大脑放屁并将它们存储为字符串¹,否则实际上是一个大整数。您无法对其进行算术运算³,但引擎认为它与
BIGINT
用作密钥的更大的没有任何不同。另一个普遍的事情是我尽量避免任何可能是关键字的名称(对于列、表、函数、过程......),因此需要转义。
uuid
如果打电话给他们的主要观点id
还不够,这是反对打电话给他们的观点。当然这不可能是完美的,我会避免uuid
,因为我知道它是 Postgres 中的类型名称,但到目前为止只使用过 SQL Server 的开发人员可能不知道,因为它不是保留字(甚至一个类型名称)在那里,我很可能会使用在其他地方不可移植的词。如果由于与使用其他系统的其他系统集成而有效地存储了多个代理键,那么您的内部标识符就是
id
. 就您的系统而言,其他数据是有意义的真实数据,而不是真正的代理键,并且应该以描述其内容或用途的方式命名。现实世界的示例包括 ISBN、StaffReferenceNumber/SRN、IRN、PPN ……,但您也可能有一些不太通用的东西,例如 SalesForceId 或 JoesPartStoreId。即使您在这些情况下没有定义代理键⁴,也要保留有意义的名称,而不是id
让您的规则很明显可能无法控制它们的生成和使用。[0] 或 id 或 Id,与您在其他地方遵循的大小写规则保持一致,以防您的内容最终以区分大小写的方式解释。
[1] 我仍然维护着一个在二十年前犯过这个错误的遗留系统,比我早一点。这一切都有效,但当然存在存储大小和性能“注意事项”,有趣的错误²会导致无效的 UUID 值,例如出现空字符串。
[2] 我也把过去的坏同事,包括多年前几次搞砸的年轻大卫斯皮莱特算作业务中的错误!
[3] 好吧,如果你足够努力的话,你可以,但不能使用任何内置函数。
[4] 无论如何,在这些情况下,我总是有一个代理键。这意味着只有您的错误会导致诸如重复键或需要影响许多外键的昂贵的主键值更改之类的问题,而不是感激处理其他系统的错误。
“uuid”不是SQL关键字。既不在标准 SQL 中,也不在PostgreSQL中。它是数据类型
uuid
的名称——从技术上讲,它不反对使用“uuid”作为标识符(即使没有双引号)。“id”是自 SQL:2011 以来标准 SQL 中的非保留关键字。但非保留关键字可以自由用作标识符。
所以你可以使用任何一个。并不意味着你应该。我个人的观点是“id”(以及“uuid”)的描述性不够强。我认为“id”的广泛使用是一种反模式。关系数据库中的任何重要查询都会连接多个表。然后你会得到多个列,全部命名为“id”,你必须对表进行限定或处理别名。虽然您仍然可以(甚至应该)这样做,但最好不要这样做。
最重要的是,我避免将基本类型名称作为标识符。不必要的混乱。令人困惑的错误消息、搜索问题、错字陷阱等。
使用描述性的、合法的、小写的、不带引号的标识符,尽可能短,尽可能长。
有关的:
我首选的命名模式是使用“foo_id”作为名为“foo”的表的代理主键列的名称。这是我的foo实体的ID,无论其数据类型如何。我对引用它的任何外键列使用相同的名称(具有相同的内容)。列上的标签代表其中的内容,查询一目了然。快速即席查询可以使用.
USING (foo_id)
我通常不在列名中包含数据类型。(除非这是该术语的常见做法。)这太吵了。我不叫我的价格列
"price_numeric",也不叫我的名字列"surname_text"。如果您必须将foo_id
列的数据类型从更改integer
为bigint
怎么办?您不想更改列名并将该更改传播到所有书面代码......因此,我使用“foo_id”,而不是
“uuid”或“id_uuid”。普通用户只需要知道“foo_id”是“foo”表的唯一(PK)ID列。数据类型是对特殊/高级目的感兴趣的实现细节。