您对使用UUID作为数据库行标识符有何看法,尤其是在Web应用程序中?

时间:2008-08-08 13:55:49

标签: database web-applications uuid

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

http://example.com/user/783

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

UUID / GUID会成为更好的解决方案吗?然后我可以设置这样的网址:

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

不完全简洁,但显示的用户隐含信息较少。当然,它隐藏着“通过默默无闻的安全”,这无法取代适当的安全性,但它似乎至少更加安全。

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

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


更新:对于那些询问只是在URL中使用用户名的人(例如,http://example.com/user/yukondude),这对于名称唯一的对象实例很有效,但是那些数以万计的网络应用对象呢?真的只能用数字来识别吗?订单,交易,发票,重复图像名称,stackoverflow问题,......

15 个答案:

答案 0 :(得分:32)

我不能说你问题的网络方面。但是uuids非常适合n层应用程序。 PK生成可以分散:每个客户端生成它自己的pk而没有冲突的风险。 速度差异通常很小。

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

我在Firebird上广泛使用它们并建议。

答案 1 :(得分:28)

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

答案 2 :(得分:23)

我可以回答你,在SQL服务器中,如果你使用uniqueidentifier(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将用于Web应用程序中的联接和guid。这个表格非常窄,查询速度非常快

答案 3 :(得分:9)

为什么要将主键与URI结合使用?

为什么不让你的URI密钥是人类可读的(或根据你的需要不可思议),以及你的主索引整数,这样你就能充分利用这两个世界。很多博客软件都会这样做,其中条目的公开id由'slug'标识,并且数字id隐藏在系统内部。

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

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

答案 4 :(得分:4)

我们使用GUID作为所有表的主键,因为它兼作MS SQL Server Replication的RowGUID。当客户突然在世界其他地方开办公室时,这很容易......

答案 5 :(得分:4)

而不是像这样的网址:

http://example.com/user/783

为什么没有:

http://example.com/user/yukondude

哪种对人类更友好,并且不泄漏那么一点信息?

答案 6 :(得分:4)

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

答案 7 :(得分:3)

这还取决于您对应用程序的关注程度。对于n层应用程序,GUID / UUID更易于实现,并且更容易在不同数据库之间移植。要生成Integer键,某些数据库本身支持序列对象,有些需要自定义构造序列表。

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

答案 8 :(得分:3)

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

创建一个可以映射到URL的较短ID,或强制实施唯一的用户名约定(http://example.com/user/brianly)。 37Signals的那些人可能会因为担心网络应用程序而担心这样的问题。

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

答案 9 :(得分:2)

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

我的意见是,最好使用整数并使用简短易懂的网址。

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

对于普通用户来说,拥有长期难看的UUID网址似乎更像是一种关闭。

答案 10 :(得分:2)

我使用学生管理系统,该系统使用整数形式的UUID。他们有一个表格,可以保存下一个唯一ID。

虽然这对于架构观点来说可能是一个好主意,但它使得每天的工作变得困难。有时需要进行批量插入,并且使用UUID会使这非常困难,通常需要编写游标而不是简单的SELECT INTO语句。

答案 11 :(得分:1)

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

答案 12 :(得分:1)

Youtube使用11个具有base64编码的字符,提供11 ^ 64的可能性,并且通常可以很容易地编写它们。我不知道这是否会提供比完整的UUID更好的性能。转换为以64为基数的UUID的大小将是我认为的两倍。

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

答案 13 :(得分:1)

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

答案 14 :(得分:-1)

只要您使用具有高效存储空间的数据库系统,无论如何硬盘驱动器都很便宜......

我知道GUID可能是一段时间可以工作并带来一些查询开销,但从安全角度来看它们是一个救世主。

当形成模糊的URI并使用表,记录和列定义的安全性构建规范化的数据库时,他们非常适合考虑安全性,你不能使用GUID来解决这个问题,尝试使用基于整数的id。