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


76

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

http://example.com/user/783

然后假设存在ID为782、781,...,2和1的用户。假设所讨论的Web应用足够安全,可以防止人们输入其他数字来查看未经授权的其他用户,简单的顺序分配的代理密钥也会“泄漏”实例总数(比该实例旧),在这种情况下为用户,这可能是特权信息。(例如,我是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)的用户来说,这对于名称唯一的对象实例非常适用,但是数十亿个Web只能通过数字识别的应用程序对象?订单,交易,发票,重复的图像名称,stackoverflow问题,...

Answers:


34

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

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

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


18
base64?如果您没有UUID的本机数据类型,请删除破折号并粘贴在byte(32)中。当您需要UUID时,这可能比在base64中编码/从base64编码/解码要快。
2011年

29

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


1
如果您可以提供有关在何处看到的更多详细信息,将很有帮助。数据库/表的大小?数据库后端?访问模式(查询是什么样的)……等等?
加伦

12
这怎么是答案。
davidahines 2013年

16
这是支持数学理论的传闻证据,即连接和索引整数将比长(ish)字符串快。
亚当·塔特尔

23

我可以回答您,在SQL Server中,如果您使用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应用程序中的向导。该表将非常狭窄,并且应该可以快速查询


10

为什么将主键与URI配对?

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

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

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


8
ID而非堆栈上的堆栈溢出索引。尝试更改页面顶部的子弹,然后按Enter。它将根据ID(5949)301将您重定向到该页面的规范URL,并忽略该条。在服务器上,它将该段与已存储/生成的段进行比较。如果不相同,则返回301。但是,通过查找ID(5949)可以找到该值。
Guy 2015年

4

而不是像这样的URL:

http://example.com/user/783

为什么不拥有:

http://example.com/user/yukondude

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


如果昵称不是唯一的,或者说书名被用作链接并进行了更改-这对seo和用户书签不利。
ZiiMakc

4

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


我认为问题的目的不是要有使用UUID的安全方法。据我了解,该主题是该决定的实际后果。而且您的方案不会增加安全性,而且会浪费CPU周期!
Patrick Cornelissen 2013年

4

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


3

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

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

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


这是不适用的,您不需要在网址中显示uuid。
davidahines 2013年

3
提问者@dah在问题的URL中提到了它的使用。
Brian Lyttle

3

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

整数键(我没有数字)可能为查询和索引性能以及空间使用情况提供了优势。使用数字键直接进行DB查询也容易得多,因为易于记忆,因此减少了复制/粘贴操作。


2

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

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


2

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

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

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

在我看来,拥有冗长的UUID网址似乎更像是对普通用户的关闭。


感谢您的意见。我研究了使用UUID作为主键及其存在的所有可能缺点的几天,直到我意识到就我而言,唯一的优点(隐藏业务信息)不值得。
Jan-Philip Gehrcke博士,2015年

1

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



1

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

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


-1

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.