RDBM和SQL数据库中有关主键,自动递增和UUID的最佳实践

Rad*_*Rad 4 sql uuid rdbms database-design

我们正在为用户实体设计一个表。唯一不平凡的要求是应该有一个指向用户实体的永久URL(例如,他们的个人资料)。网络上有很多关于int / long vs UUID的信息。但是我仍然不清楚。

  1. 考虑到配置文件包含私人信息这一事实,在URL中嵌入可预测的ID并不是一个好主意。我对吗?
  2. 为了满足第一个要求,我可以将主键作为UUID并将其嵌入URL中。但是有两个问题。无论如何,我是否应该担心以UUID作为主键会降低性能?索引,插入,选择,加入?

话虽如此,以下哪一项更好(相对于上述而言)?

CREATE TABLE users(
  pk UUID NOT NULL,
  .....
  PRIMARY KEY(pk)
);
Run Code Online (Sandbox Code Playgroud)

要么

CREATE TABLE users(
  pk INT NOT NULL AUTO_INCREMENT,
  id UUID NOT NULL,
  .....
  PRIMARY KEY(pk),
  UNIQUE(id)
);
Run Code Online (Sandbox Code Playgroud)

Ami*_*han 13

使用 UUID 作为pk: 第一个问题是,UUID 占用的9x存储空间大于int。第二个问题是,如果您需要更频繁地排序pk,甚至不要考虑 UUID。UUID aspk不会影响where条件或除 之外的其他条件的时间复杂度sort

使用intaspk:很容易猜到。暴力攻击者会喜欢这个。这是唯一的问题,也是最大的问题。

使用intas pkbut,同时保留 UUID:如果 UUID 不是,pk那么通过 UUID 搜索的时间复杂度将会增加。尽管,所有关系都将由 维护int,但是,当您通过 UUID 搜索时,这将需要时间。由于关系已开启int9x存储问题就在这里解决了。

  • 没有人*永远*会按 UUID 排序。唯一的过滤器将是“where user.uuid = some_uuid”。关于索引选择(where),我不相信 UUID 会变慢,因为所有值都将在表中完美分布。自动增量的分布会很差——所有最近的记录都会聚集在一起,从而降低索引性能。对于存储大小,UUID 仅是 bigint 大小的两倍。 (8认同)

Sar*_*oev 11

我看到一篇很好的文章,解释了使用 UUID 作为主键的优点和缺点。最后,它建议对 PK 使用增量整数,对外部世界使用 UUID。永远不要把你的PK暴露在外面。

\n
\n

在几种不同的环境中使用的一种解决方案对我来说很有效,简而言之,可以同时使用这两种情况。(请注意:这不是一个好的解决方案 \xe2\x80\x94 请参阅\n关于下面对原始帖子的回复的注释)。在内部,让数据库使用小型、高效、数字\n顺序键(无论是 int 还是 bigint)来管理数据关系。然后添加一个用 UUID 填充的列(可能作为插入时的触发器)。在数据库本身的范围内,可以使用常用的 PK 和 FK 来管理关系。

\n

但是,当对数据的引用需要暴露给\n外部世界时,即使 \xe2\x80\x9coutside\xe2\x80\x9d 意味着另一个内部系统,\n它们也必须仅依赖于 UUID。这样,如果您确实需要更改\n内部主键,则可以确保其\xe2\x80\x99 的范围仅适用于一个\n数据库。(注:正如克里斯所观察到的,这完全是错误的)

\n

我们在另一家公司对客户数据使用了这种策略,只是为了避免 \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n的\xe2\x80\x9c:可猜测的\xe2\x80\x9d问题::(注意:避免与预防不同,请参见下文)。

\n

在另一种情况下,我们会生成 \xe2\x80\x9cslug\xe2\x80\x9d 文本(例如在像这样的博客文章中),这将使 URL 更加人性化。如果我们有重复项,我们只需附加一个哈希值。

\n

即使作为 \xe2\x80\x9c 辅助主键 \xe2\x80\x9d,以字符串形式使用 UUID 也是错误的:使用内置数据库机制,因为值\n存储为 8 字节整数,我会期望。

\n

使用整数是因为它们很有效。此外,还使用 ​​UUID 的数据库实现来进行模糊处理的任何外部引用。

\n
\n

https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439

\n


The*_*ler 10

这个问题非常基于意见,所以这是我的。

我的看法是使用第二个,一个独立于 PK 的 UUID。事情是:

  • PK 是独一无二的,不会向公众公开。
  • UUID 是唯一的,可能会向公众公开。

如果出于任何原因,UUID 遭到破坏,您将需要更改它。更改 PK 可能会很昂贵并且有很多副作用。如果 UUID 与 PK 是分开的,那么它的更改(虽然不是微不足道的)产生的影响要小得多。

  • @ymajoros 并非所有资源都是完全私有的。一个例子是“任何知道链接的人”都可以访问的东西。谷歌通过文档和表格之类的东西来做到这一点。在这种情况下,自动递增 ID 应该保密,以防止通过融合式攻击来发现文档。在这种情况下,UUID 会非常有用,因为没有真正的模式可供猜测,因此查找它们非常耗时。因此,它们提供了可接受的保护层,同时保持易于访问。安全性不是简单地打开/关闭。安全始终是妥协的程度,包括各种风险和可用性权衡。 (8认同)
  • 数字 ID 或 UUID 也不应该保密。安全性不应该基于不可猜测的 ID,并且无论如何都应该检查访问权限。 (5认同)
  • 我认为 @JoelMellon 想说的是,出于某种原因,您可能不希望外部用户以某种方式确定您系统中的交易记录数量,因为它们可以通过有序的数字 ID 公开访问。好吧,它们是公开的,但没有人可以确切地知道您拥有多少资源。 (3认同)

vy3*_*y32 8

不要将\xe2\x80\x99 设为数据库主键:这将在您将来想要更改数据库技术时导致问题。如果您的数量不断增加,您的竞争对手就会知道您拥有多少用户以及添加新用户的速度。

\n


Kam*_*ski 6

从我的角度来看,这实际上是一个选择问题,这个问题可以提出基于观点的答案。我经常做的事,即使有多余,我还是在自动增量列上创建了主键(我称之为技术键),以使其在数据库中保持一致,并允许“主键”发生更改,以防在设计阶段出现问题。如果其他任何表中的外键约束都指向该键,则还允许占用更少的空间,并且我使候选键唯一且不为null。

除非您决定,否则通常不会向最终用户显示技术密钥。对于出于某些目的(例如修改日期,创建日期,版本,更改记录的用户等)而仅出于数据库目的保留的其他技术专栏,这可以是相同的。

在这种情况下,我会选择第二种方法,但会稍作修改:

CREATE TABLE users(
  pk INT NOT NULL AUTO_INCREMENT,
  id UUID NOT NULL,
  .....
  PRIMARY KEY(pk),
  UNIQUE(id)
);
Run Code Online (Sandbox Code Playgroud)

  • @Kamil,当存在关系时,应该使用 auto-inc 作为 FK 吗?但这是否意味着简单查询需要额外的连接?例如,一对多的客户付款关系,意味着要获取 customerKey 的付款,我们将使用 auto-inc 加入客户的付款,其中 customerKey = key from req,而不是仅仅查询付款表,其中 customerKey = key来自请求。 (3认同)