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

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

What's your opinion on using UUIDs as database row identifiers, particularly in web apps?

为了简化和(假定)速度,我一直首选使用长整数作为数据库中的主键。但是,当对对象实例使用REST或类似Rails的URL方案时,我将得到这样的URL:

1
http://example.com/user/783

然后假设存在ID为782、781,...,2和1的用户。假设所讨论的Web应用足够安全,可以防止人们输入其他数字来查看未经授权的其他用户,简单的顺序分配的代理密钥也会"泄漏"实例总数(比该实例旧),在这种情况下为用户,这可能是特权信息。 (例如,我是stackoverflow中的用户#726。)

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

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

并非十分简洁,但所显示的用户隐含信息较少。当然,它带有"模糊不清的安全性",这不能代替适当的安全性,但似乎至少更安全一些。

对于Web可寻址对象实例,实现UUID的成本和复杂性是否值得这样做?我认为我仍然想使用整数列作为数据库PK,只是为了加快连接速度。

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

更新:对于那些询问仅使用URL中的用户名(例如http://example.com/user/yukondude)的用户来说,这对于名称唯一的对象实例非常适用,但无数的网络又如何呢?只能通过数字识别的应用程序对象?订单,交易,发票,重复的图像名称,stackoverflow问题,...


关于您的问题,我不能说。但是uuid对于n层应用程序非常有用。 PK生成可以分散:每个客户生成自己的pk,而不会发生冲突。
而且速度差一般很小。

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

我在Firebird中广泛使用了它们,并推荐使用。


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


我可以回答您,在SQL Server中,如果您使用uniqueidentifier(GUID)数据类型并使用NEWID()函数创建值,由于页面拆分,您将得到可怕的碎片。原因是使用NEWID()时,生成的值不是连续的。 SQL 2005添加了NEWSEQUANTIAL()函数来解决这一问题

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

例如

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

1和2将用于Web应用程序的联接和向导中。该表将非常狭窄,并且应该可以快速查询


为什么将主键与URI耦合?

为什么不让URI密钥对人类可读(或根据您的需要是不可猜测的)以及基于主索引整数的,那么您就可以兼得两者。许多博客软件都这样做,其中条目的公开ID由"子弹"标识,而数字ID隐藏在系统内部。

这里增加的好处是您现在有了一个非常不错的URL结构,这对SEO很有用。显然,对于事务而言,这不是一件好事,但是对于诸如stackoverflow之类的事情而言,这很重要(请参见URL顶部...)。获得独特性并不难。如果您真的很担心,可以将表子的哈希存储在表中的某个位置,并在插入之前进行查找。

编辑:Stackoverflow不太使用我描述的系统,请参见下面的盖伊评论。


我们将GUID用作所有表的主键,因为它是MS SQL Server复制的RowGUID的两倍。当客户突然在世界其他地方开设办事处时,这非常容易。


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


而不是像这样的URL:

1
http://example.com/user/783

为什么不拥有:

1
http://example.com/user/yukondude

哪一个对人类更友好,并且不会泄漏出很少的信息?


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

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


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

创建一个较短的ID,您可以将其映射到URL,或强制执行唯一的用户名约定(http://example.com/user/brianly)。 37Signals的家伙可能会嘲笑您担心Web应用程序之类的问题。

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


我已经在真实的Web应用程序中尝试过。

我的观点是,最好使用整数并具有简短的可理解网址。

作为开发人员,看到连续的整数并知道一些有关总记录数的信息正在泄漏,这让您感到有些恐惧,但是说实话-大多数人可能不在乎,而且这些信息对我的业务从未真正重要。

在我看来,冗长的UUID网址看起来更像是普通用户无法使用的网址。


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

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


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

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


我认为这是引起准宗教辩论的问题之一,谈论起来几乎是徒劳的。我只是说用你喜欢的。在99%的系统中,无论您使用哪种类型的密钥,因此使用一种类型的密钥(而不是另一种类型)的好处(在其他文章中都有说明)都不会成为问题。


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


只要您使用具有高效存储的数据库系统,如今无论如何,HDD还是便宜的。

我知道GUID有时可能会很麻烦,并带有一些查询开销,但是从安全角度来看,它们是一个救星。

通过模糊性来考虑安全性,它们很适合在形成模糊的URI并使用Table,Record和Column定义的安全性来构建归一化的DB时,GUID不会出错,请尝试使用基于整数的id来实现。


推荐阅读