RDBM 和 SQL 数据库中主键、自动增量和 UUID 的最佳实践
Best practices on primary key, auto-increment, and UUID in RDBMs and SQL databases
我们正在为用户实体设计 table。唯一重要的要求是用户实体(例如他们的个人资料)应该有一个永久的 URL。网络上有很多关于 int/long 与 UUID 的对比。但我仍然不清楚。
- 考虑到配置文件包含私人信息这一事实,在 URL 中嵌入谓词 table ID 并不是一个好主意。我说得对吗?
- 为了满足第一个要求,我可以将主键作为 UUID 并将其嵌入 URL。但是有两个问题。无论如何,我是否应该担心将 UUID 作为主键的性能损失?索引、插入、选择、连接?
话虽如此,以下哪一项更好(相对于上述)?
CREATE TABLE users(
pk UUID NOT NULL,
.....
PRIMARY KEY(pk)
);
或
CREATE TABLE users(
pk INT NOT NULL AUTO_INCREMENT,
id UUID NOT NULL,
.....
PRIMARY KEY(pk),
UNIQUE(id)
);
这其实是一个选择题,这个问题可以从我的角度提出基于意见的答案。我总是做的,即使它是多余的,我在自动增量列上创建主键(我称之为技术键)以保持它在数据库中的一致性,允许 "primary key" 在设计阶段出现问题时进行更改并且还允许使用更少的 space 以防任何其他 table 中的外键约束指向该键,并且我还使候选键唯一且不为空。
技术密钥通常不会向最终用户显示,除非您决定这样做。对于您出于任何可能需要的目的(例如修改日期、创建日期、版本、更改记录的用户等)而仅在数据库级别保留的其他技术列,这可能是相同的。
在这种情况下,我会选择你的第二个选项,但稍作修改:
CREATE TABLE users(
pk INT NOT NULL AUTO_INCREMENT,
id UUID NOT NULL,
.....
PRIMARY KEY(pk),
UNIQUE(id)
);
这个问题是基于意见的,所以这是我的问题。
我的做法是使用第二个,一个独立于 PK 的 UUID。事情是:
- PK独特,不暴露于public。
- UUID 是唯一的,可能会暴露给 public。
如果出于任何原因 UUID 遭到泄露,您将需要更改它。更改 PK 可能会很昂贵并且会产生很多副作用。如果 UUID 与 PK 是分开的,那么它的变化(虽然不是微不足道的)的后果要小得多。
不要让它成为你的数据库主键:这会在你想改变你的数据库技术的未来带来问题。如果你让它越来越多,你的竞争对手就会知道你有多少用户以及你添加新用户的速度有多快。
我看到一篇很好的文章,它解释了使用 UUID 作为主键的优缺点。最后,它建议同时使用 PK 的增量整数和外部世界的 UUID。永远不要把你的PK暴露在外面。
One solution used in several different contexts that has worked for me
is, in short, to use both. (Please note: not a good solution — see
note about response to original post below). Internally, let the
database manage data relationships with small, efficient, numeric
sequential keys, whether int or bigint. Then add a column populated
with a UUID (perhaps as a trigger on insert). Within the scope of the
database itself, relationships can be managed using the usual PKs and
FKs.
But when a reference to the data needs to be exposed to the
outside world, even when “outside” means another internal system, they
must rely only on the UUID. This way, if you ever do have to change
your internal primary keys, you can be sure it’s scoped only to one
database. (Note: this is just plain wrong, as Chris observed)
We used this strategy at a different company for customer data, just to avoid
the “guessable” problem. (Note: avoid is different than prevent, see
below).
In another case, we would generate a “slug” of text (e.g. in
blog posts like this one) that would make the URL a little more human
friendly. If we had a duplicate, we would just append a hashed value.
Even as a “secondary primary key”, using a naive use of UUIDs in
string form is wrong: use the built-in database mechanisms as values
are stored as 8-byte integers, I would expect.
Use integers because they are efficient. Use the database
implementation of UUIDs in addition for any external reference to
obfuscate.
https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439
将UUID用作pk
:第一个问题是,UUID比int
占用9x
存储空间。第二个问题是,如果您需要更频繁地按 pk
排序,甚至不要考虑 UUID。 pk
的 UUID 不会影响 where
条件或除 sort
.
以外的其他条件的时间复杂度
将int
用作pk
:很容易猜到。蛮力攻击者会喜欢这个。这是唯一的问题,也是最大的问题。
Uusing int
as pk
but, keeping UUID as : If the UUID is not pk
then the time complexity will be增加了通过 UUID 搜索。尽管,所有关系都将由 int
维护,但是,当您按 UUID 搜索时,这将需要时间。由于关系在 int
,9x
存储问题已在此处解决。
我们正在为用户实体设计 table。唯一重要的要求是用户实体(例如他们的个人资料)应该有一个永久的 URL。网络上有很多关于 int/long 与 UUID 的对比。但我仍然不清楚。
- 考虑到配置文件包含私人信息这一事实,在 URL 中嵌入谓词 table ID 并不是一个好主意。我说得对吗?
- 为了满足第一个要求,我可以将主键作为 UUID 并将其嵌入 URL。但是有两个问题。无论如何,我是否应该担心将 UUID 作为主键的性能损失?索引、插入、选择、连接?
话虽如此,以下哪一项更好(相对于上述)?
CREATE TABLE users(
pk UUID NOT NULL,
.....
PRIMARY KEY(pk)
);
或
CREATE TABLE users(
pk INT NOT NULL AUTO_INCREMENT,
id UUID NOT NULL,
.....
PRIMARY KEY(pk),
UNIQUE(id)
);
这其实是一个选择题,这个问题可以从我的角度提出基于意见的答案。我总是做的,即使它是多余的,我在自动增量列上创建主键(我称之为技术键)以保持它在数据库中的一致性,允许 "primary key" 在设计阶段出现问题时进行更改并且还允许使用更少的 space 以防任何其他 table 中的外键约束指向该键,并且我还使候选键唯一且不为空。
技术密钥通常不会向最终用户显示,除非您决定这样做。对于您出于任何可能需要的目的(例如修改日期、创建日期、版本、更改记录的用户等)而仅在数据库级别保留的其他技术列,这可能是相同的。
在这种情况下,我会选择你的第二个选项,但稍作修改:
CREATE TABLE users(
pk INT NOT NULL AUTO_INCREMENT,
id UUID NOT NULL,
.....
PRIMARY KEY(pk),
UNIQUE(id)
);
这个问题是基于意见的,所以这是我的问题。
我的做法是使用第二个,一个独立于 PK 的 UUID。事情是:
- PK独特,不暴露于public。
- UUID 是唯一的,可能会暴露给 public。
如果出于任何原因 UUID 遭到泄露,您将需要更改它。更改 PK 可能会很昂贵并且会产生很多副作用。如果 UUID 与 PK 是分开的,那么它的变化(虽然不是微不足道的)的后果要小得多。
不要让它成为你的数据库主键:这会在你想改变你的数据库技术的未来带来问题。如果你让它越来越多,你的竞争对手就会知道你有多少用户以及你添加新用户的速度有多快。
我看到一篇很好的文章,它解释了使用 UUID 作为主键的优缺点。最后,它建议同时使用 PK 的增量整数和外部世界的 UUID。永远不要把你的PK暴露在外面。
One solution used in several different contexts that has worked for me is, in short, to use both. (Please note: not a good solution — see note about response to original post below). Internally, let the database manage data relationships with small, efficient, numeric sequential keys, whether int or bigint. Then add a column populated with a UUID (perhaps as a trigger on insert). Within the scope of the database itself, relationships can be managed using the usual PKs and FKs.
But when a reference to the data needs to be exposed to the outside world, even when “outside” means another internal system, they must rely only on the UUID. This way, if you ever do have to change your internal primary keys, you can be sure it’s scoped only to one database. (Note: this is just plain wrong, as Chris observed)
We used this strategy at a different company for customer data, just to avoid the “guessable” problem. (Note: avoid is different than prevent, see below).
In another case, we would generate a “slug” of text (e.g. in blog posts like this one) that would make the URL a little more human friendly. If we had a duplicate, we would just append a hashed value.
Even as a “secondary primary key”, using a naive use of UUIDs in string form is wrong: use the built-in database mechanisms as values are stored as 8-byte integers, I would expect.
Use integers because they are efficient. Use the database implementation of UUIDs in addition for any external reference to obfuscate.
https://tomharrisonjr.com/uuid-or-guid-as-primary-keys-be-careful-7b2aa3dcb439
将UUID用作pk
:第一个问题是,UUID比int
占用9x
存储空间。第二个问题是,如果您需要更频繁地按 pk
排序,甚至不要考虑 UUID。 pk
的 UUID 不会影响 where
条件或除 sort
.
将int
用作pk
:很容易猜到。蛮力攻击者会喜欢这个。这是唯一的问题,也是最大的问题。
Uusing int
as pk
but, keeping UUID as : If the UUID is not pk
then the time complexity will be增加了通过 UUID 搜索。尽管,所有关系都将由 int
维护,但是,当您按 UUID 搜索时,这将需要时间。由于关系在 int
,9x
存储问题已在此处解决。