79

为了简单和(假设的)速度,我一直更喜欢使用长整数作为数据库中的主键。但是当对对象实例使用REST或类似 Rails 的 URL 方案时,我最终会得到这样的 URL:

http://example.com/user/783

然后假设还有 ID 为 782、781、...、2 和 1 的用户。假设有问题的 Web 应用程序足够安全,可以防止人们在未经授权的情况下输入其他号码查看其他用户,a简单的顺序分配的代理键也“泄露”了实例的总数(比这个更早),在这种情况下是用户,这可能是特权信息。(例如,我是 stackoverflow 中的用户 #726。)

UUID / GUID会是更好的解决方案吗?然后我可以像这样设置 URL:

http://example.com/user/035a46e0-6550-11dd-ad8b-0800200c9a66

不完全简洁,但显示的有关用户的隐含信息较少。当然,它带有“通过默默无闻的安全”的味道,这不能替代适当的安全性,但它似乎至少更安全一点。

这种好处是否值得为 Web 可寻址对象实例实现 UUID 的成本和复杂性?我认为我仍然想使用整数列作为数据库 PK 来加速连接。

还有 UUID 的数据库内表示的问题。我知道 MySQL 将它们存储为 36 个字符的字符串。Postgres 似乎有更有效的内部表示(128 位?),但我自己没有尝试过。有人对此有经验吗?


更新:对于那些询问仅在 URL 中使用用户名(例如http://example.com/user/yukondude)的人来说,这对于具有唯一名称的对象实例来说工作得很好,但是无数的网络呢?真正只能通过数字识别的应用程序对象?订单、交易、发票、重复的图像名称、stackoverflow 问题……

4

15 回答 15

34

我不能说你问题的网络方面。但是 uuid 非常适合 n 层应用程序。PK 生成可以去中心化:每个客户端生成自己的 pk,没有冲突的风险。而且速度差异一般很小。

确保您的数据库支持高效的存储数据类型(16 字节,128 位)。至少您可以在 base64 中编码 uuid 字符串并使用 char(22)。

我已经将它们与 Firebird 一起广泛使用并推荐。

于 2008-08-08T14:03:00.833 回答
29

值得一提的是,我已经看到一个长时间运行的存储过程(9 秒以上)只需从 GUID 主键切换到整数就可以缩短到几百毫秒的运行时间。这并不是说显示GUID 是一个坏主意,但正如其他人所指出的那样,根据定义,加入它们并为它们编制索引不会像使用整数那样快。

于 2008-08-08T15:20:35.857 回答
23

我可以回答你,如果你在 SQL Server 中使用唯一标识符 (GUID) 数据类型并使用 NEWID() 函数来创建值,你会因为页面拆分而产生可怕的碎片。原因是使用 NEWID() 时生成的值不是连续的。SQL 2005 添加了 NEWSEQUANTIAL() 函数来解决这个问题

仍然使用 GUID 和 int 的一种方法是在表中包含一个 guid 和一个 int,以便该 guid 映射到该 int。guid 在外部使用,但在数据库内部使用 int

例如

457180FB-C2EA-48DF-8BEF-458573DA1C10    1
9A70FF3C-B7DA-4593-93AE-4A8945943C8A    2

1 和 2 将用于网络应用程序中的连接和 guid。这个表会很窄,查询起来应该很快

于 2008-08-08T14:05:56.630 回答
10

为什么要将主键与 URI 结合起来?

为什么不让你的 URI 键是人类可读的(或不可猜测的,取决于你的需要),并且你的主索引整数基于,这样你就可以两全其美。许多博客软件都是这样做的,其中条目的公开 id 由“slug”标识,而数字 id 隐藏在系统内部。

这里的额外好处是您现在拥有一个非常好的 URL 结构,这对 SEO 有好处。显然,对于事务来说这不是一件好事,但对于像 stackoverflow 这样的东西来说,这很重要(参见顶部的 URL ...)。获得独特性并不难。如果您真的很担心,请将 slug 的哈希存储在某个表中的某个地方,并在插入之前进行查找。

编辑: Stackoverflow 并没有完全使用我描述的系统,请参阅下面 Guy 的评论。

于 2008-09-16T05:24:56.510 回答
4

而不是这样的 URL:

http://example.com/user/783

为什么没有:

http://example.com/user/yukondude

哪个对人类更友好并且不会泄露那一点点信息?

于 2008-08-08T18:24:15.797 回答
4

您可以使用与行号相关但不连续的整数。例如,您可以取序列 ID 的 32 位并使用固定方案重新排列它们(例如,位 1 变为位 6,位 2 变为位 15,等等)。
这将是一种双向加密,您将确保两个不同的 ID 始终具有不同的加密。
如果花时间生成足够的 ID 并获取架构,这显然很容易解码,但是,如果我正确理解您的问题,您只是不想太容易泄露信息。

于 2008-08-12T18:20:16.023 回答
4

我们使用 GUID 作为所有表的主键,因为它兼作 MS SQL Server 复制的 RowGUID。当客户突然在世界的另一个地方开设办公室时,它变得非常容易......

于 2008-08-12T21:00:12.877 回答
3

我不认为 GUID 会给您带来很多好处。用户讨厌冗长、难以理解的 URL。

创建一个较短的 ID,您可以将其映射到 URL,或强制执行唯一的用户名约定 ( http://example.com/user/brianly )。37Signals的人可能会嘲笑你在涉及网络应用时担心这样的事情。

顺便说一句,您可以强制您的数据库从基值开始创建整数 ID。

于 2008-08-08T15:10:04.240 回答
3

这还取决于您关心您的应用程序的内容。对于 n 层应用程序,GUID/UUID 更易于实现,并且更易于在不同数据库之间移植。为了生成整数键,一些数据库本身支持序列对象,而一些数据库需要自定义构建序列表。

整数键可能(我没有数字)为查询和索引性能以及空间使用提供了优势。使用数字键进行直接数据库查询也更容易,复制/粘贴更少,因为它们更容易记住。

于 2008-09-16T00:31:55.903 回答
2

我使用一个学生管理系统,它使用整数形式的 UUID。他们有一个包含下一个唯一 ID 的表。

尽管从架构的角度来看这可能是一个好主意,但它使日常工作变得困难。有时需要进行批量插入,而拥有 UUID 会使这变得非常困难,通常需要编写游标而不是简单的 SELECT INTO 语句。

于 2008-08-08T13:59:46.673 回答
2

我在真正的网络应用程序中都试过了。

我的观点是最好使用整数并有简短易懂的 URL。

作为一名开发人员,看到连续整数并知道一些关于总记录数的信息正在泄漏,感觉有点糟糕,但老实说——大多数人可能并不关心,而且这些信息对我的业务从来没有真正重要过。

在我看来,长长的丑陋 UUID URL 对普通用户来说更像是一种关闭。

于 2013-10-02T03:43:39.030 回答
1

我认为在您的情况下使用 GUID 会是更好的选择。它占用更多空间,但更安全。

于 2008-08-08T14:00:49.323 回答
1

我认为这是引起准宗教辩论的问题之一,谈论几乎是徒劳的。我只想说使用你喜欢的。在 99% 的系统中,无论您使用哪种类型的密钥,使用一种类型的优势(在其他帖子中说明)永远不会成为问题。

于 2008-08-12T19:30:13.137 回答
1

YouTube 使用 11 个字符和 base64 编码,提供 11^64 种可能性,而且它们通常很容易编写。我想知道这是否会比完整的 UUID 提供更好的性能。转换为 base 64 的 UUID 将是我认为的两倍。

更多信息可以在这里找到:https ://www.youtube.com/watch?v=gocwRvLhDf8

于 2018-07-23T03:39:35.977 回答
-1

只要您使用具有高效存储的数据库系统,这些天 HDD 无论如何都很便宜......

我知道 GUID 有时可以使用并带有一些查询开销,但是从安全角度来看,它们是救世主。

通过模糊思考安全性,它们在形成模糊的 URI 和使用表、记录和列定义的安全性构建规范化 DB 时非常合适,GUID 不会出错,尝试使用基于整数的 id 来做到这一点。

于 2013-02-25T10:41:35.423 回答