什么时候你真的被迫使用UUID作为devise的一部分?

我真的不明白UUID的意义 。 我知道碰撞的可能性实际上 ,但实际上零甚至是不可能的。

有人可以举一个例子,你别无select,只能使用UUID吗? 从我见过的所有用途中,我可以看到没有UUID的替代devise。 当然,devise可能会稍微复杂一些,但至less不会有非零概率的失败。

UUID闻起来像全局variables给我。 全局variables有很多方法可以简化devise,但它只是懒惰的devise。

我为Ruby编写了UUID生成器/parsing器,所以我认为自己对这个主题有相当的了解。 有四个主要的UUID版本:

版本4的UUID本质上只是从一个密码安全的随机数发生器中随机抽取的16个字节,有一些位用来标识UUID版本和变体。 这些是非常不可能发生碰撞的,但是如果使用PRNG,或者如果碰巧确实真的真的运气真的不好的话,就会发生这种情况。

版本5和版本3 UUID分别使用SHA1和MD5散列函数,将名称空间与一段已经唯一的数据组合起来,以生成UUID。 例如,这将允许您从URL生成一个UUID。 这里的冲突只有在底层散列函数也有冲突的情况下才有可能。

版本1 UUID是最常见的。 他们使用网卡的MAC地址(除非是伪造的,应该是唯一的),再加上一个时间戳,再加上通常的位数来产生UUID。 在没有MAC地址的机器的情况下,使用密码安全的随机数发生器生成6个节点字节。 如果两个UUID按顺序快速生成,以使时间戳与先前的UUID相匹配,则时间戳记将递增1.除非发生以下情况之一,否则不应出现冲突:MAC地址被伪造; 运行两个不同的UUID生成应用程序的一台机器在同一时刻生成UUID; 两台没有网卡或没有用户级访问MAC地址的机器被赋予相同的随机节点序列,并在同一时刻生成UUID; 我们用尽字节来表示时间戳和翻转回零。

实际上,这些事件都不会在单个应用程序的ID空间内偶然发生。 除非你在互联网范围内接受身份证,或者在一个不可信的环境中,恶意的个人可能在身份冲突的情况下做不好的事情,那么这不是你应该担心的事情。 理解这一点很重要,如果您碰巧生成与我一样的第4版UUID,在大多数情况下,这并不重要。 我已经生成了一个完全不同于你的ID空间的ID。 我的应用程序永远不会知道碰撞,所以碰撞并不重要。 坦率地说,在没有恶意行为的单一应用程序空间中,即使在第4版UUID中,即使您每秒生成不lessUUID,地球上所有生命的灭绝也会在发生碰撞之前发生。

另外,2 ^ 64 * 16是256艾字节。 就像在一个应用程序空间中,您需要存储256艾字节的ID,然后才有50%的ID冲突可能性。

UUID给你买的东西很难做到,就是得到一个唯一的标识符, 而不必咨询或协调一个中央机构 。 能够在没有某种托pipe基础设施的情况下获得这样的事情的一般问题是UUID解决的问题。

我已经读过,根据生日悖论,UUID碰撞发生的几率是50%,一旦生成了2 ^ 64个UUID。 现在2 ^ 64是一个相当大的数字,但有50%的碰撞几率似乎太冒险了(例如,有5%的碰撞机会之前需要存在多less个UUID,即使这个概率太大也是如此) 。

这个分析的问题是双重的:

  1. UUID并不完全是随机的 – UUID的主要组成部分是时间和/或基于位置的。 因此,为了在碰撞中有任何真实的机会,需要从不同的UUID生成器同时生成冲突的UUID。 我想说,虽然有一个合理的机会可能会同时生成几个UUID,但是还有足够的其他gunk(包括位置信息或随机位)使这个非常小的UUID之间的冲突几乎不可能。

  2. 严格来说,UUID只需要在可能与之比较的其他UUID集合中是唯一的。 如果您生成的UUID用作数据库键,那么使用相同的UUID标识COM接口的恶意备用Universe中的其他位置无关紧要。 就像Alpha-Centauri上有人(或其他)被称为“Michael Burr”的人一样,也不会造成混淆。

一切都有一个非零的机会。 我会专注于发生比UUID碰撞更多的问题(即几乎所有你能想到的)

强调“合理”,或者正如你所说的那样,“有效”:足够好的是现实世界的工作方式。 涵盖“实际独特”与“真正独特”之间差距的计算量是巨大的。 唯一性是一个收益递减的曲线。 在这条曲线的某个点上,“足够独特”的位置之间还有一条线路,然后我们非常陡峭地弯曲。 增加更多独特性的成本变得相当大。 无限的独特性有无限的成本。

相对而言,UUID / GUID是一种快速简单的计算方法,可以生成一个可合理假设为普遍唯一的ID。 这在许多需要整合来自以前未连接的系统的数据的系统中是非常重要的。 例如:如果您有一个在两个不同平台上运行的内容pipe理系统,但有时需要将内容从一个系统导入另一个系统。 你不希望ID改变,所以你从系统A的数据之间的引用保持不变,但你不希望与在系统B中创build的数据发生任何冲突。一个UUID解决了这个问题。

从来没有必要创build一个UUID。 不pipe怎么说, 离线用户都可以生成一个密钥,而且碰撞概率非常低,这是很方便的。

这可以帮助数据库复制解决scheme等…

在线用户很容易为某些东西生成唯一的密钥,而不会产生碰撞的开销或可能性,但这不是UUID的目的。

无论如何,从维基百科采取一个关于碰撞概率的词:

从这些数字的angular度来看,每年被陨石击中的风险估计是170亿的一个机会,相当于每年创造几十万亿的UUID的几率和一个副本。 换句话说,在未来100年内每秒产生10亿个UUID之后,创build一个副本的可能性大约为50%。

你身体里的每一个微粒都会同时穿过坐在椅子上的一个非零概率,你会突然发现自己坐在地板上。

你担心这个吗?

一个经典的例子是当你在两个数据库之间进行复制时。

DB(A)插入一个int ID为10的logging,同时DB(B)创build一个ID为10的logging。这是一个冲突。

有了UUID,这不会发生,因为它们不匹配。 (几乎可以确定)

如果您只是查看一个简单的数据库应用程序的替代scheme,那么在创build新对象之前每次都必须查询数据库,您很快就会发现使用UUID可以有效地降低系统的复杂性。 授予 – 如果您使用int键是32位,这将存储在128位UUID的四分之一。 授予 – UUID生成algorithm占用更多的计算能力,而不是简单地递增一个数字。 但谁在乎? pipe理“授权”来分配唯一的数字的开销很容易超过数量级,取决于您想要的唯一性ID空间。

在UUID ==懒惰的devise

我不同意它select你的战斗。 如果重复的UUID在统计学上是不可能的,mathcertificate了,那么为什么要担心呢? 花时间围绕您的小型N UUID生成系统进行devise是不切实际的,总有十几种其他方式可以改进您的系统。

我有一个避免UUID的scheme。 在某个地方build立一个服务器,这样每次某个软件需要一个通用唯一的标识符时,他们就联系该服务器,然后交出一个。 简单!

除此之外还有一些实际的问题,即使我们忽略了直接的恶意。 特别是,该服务器可能会失败或无法从互联网的一部分。 处理服务器故障需要复制,而且这很难做到正确(请参阅有关Paxosalgorithm的文献,以了解build立共识的原因),而且也很慢。 而且,如果所有服务器都无法从networking的特定部分访问,则连接到该子网的所有客户端都无法做任何事情,因为他们都将等待新的ID。

所以…使用一个简单的概率algorithm来生成它们,在地球的一生中不可能失败,或者(基金和)build立一个主要的基础设施,这个基础设施将成为部署PITA并经常失败。 我知道我会去哪一个。

我并没有全面谈到碰撞的可能性。 我不在乎碰撞。 虽然我关心表演。

https://dba.stackexchange.com/a/119129/33649

UUID是非常大的表的性能灾难。 (200K行不是“非常大”)。

当CHARCTER SET是utf8时,你的#3真的很差 – CHAR(36)占用108个字节!

UUID(GUID)非常“随机”。 在大型表上使用它们作为UNIQUE或PRIMARY键是非常低效的。 这是因为每次插入一个新的UUID或通过UUID SELECT时,必须跳转表/索引。 当表/索引太大以至于无法放入caching(请参阅innodb_buffer_pool_size,它必须小于RAM,通常为70%),则可能无法caching“下一个”UUID,因此磁盘速度较慢。 当表/索引是高速caching的20倍时,只有1/20(5%)的命中被caching – 你是I / O绑定的。

所以,除非另有说明,否则不要使用UUID

你有“小”表,或者你真的需要他们,因为从不同的地方产生独特的ID(并没有find另一种方式)。 有关UUID的更多信息: http : //mysql.rjweb.org/doc.php/uuid (它包括在标准的36个字符的UUID和BINARY(16)之间转换的函数。

在同一个表中同时拥有一个UNIQUE AUTO_INCREMENT和一个UNIQUE UUID是很浪费的。

发生INSERT时,必须检查所有唯一/主键的重复项。 独特的密钥足以满足InnoDB对主密钥的要求。 二进制(16)(16字节)是有点庞大(反对使它成为PK的论据),但没有那么糟糕。 如果您有辅助键,体积就很重要。 InnoDB在每个二级密钥的末尾悄悄地贴上PK。 这里的主要教训是尽量减less二级键的数量,特别是对于非常大的表格。 为了比较:INT UNSIGNED是4个字节,范围是0-4亿。 BIGINT是8个字节。

使用版本1algorithm似乎在约束条件下不可能发生冲突,即从相同的MAC地址产生的每毫秒less于10个UUID

从概念上讲,UUID的原始(版本1)生成scheme是将UUID版本与生成UUID的计算机的MAC地址连接在一起,并且自西部公历采用以来的100纳秒间隔。 实际中,实际的algorithm比较复杂。 这个计划受到了批评,因为它不够“不透明”。 它揭示了产生UUID的计算机的身份和它所做的时间。

有人纠正我,如果我误解了它是如何工作的

对于那些说UUID是不好的devise,因为他们可以 (以一些可笑的小概率)相撞,而你的数据库生成的密钥不会…你知道人为错误的机会造成你的数据库生成的键冲突,因为一些联合国需要远远高于UUID4碰撞机会的FAR FAR FAR。 我们知道 ,如果数据库重新创build,它将再次启动ID为1,当我们确定我们永远不需要时,有多less人不得不重新创build一个表? 我会把钱放在UUID安全的地方,因为任何事情都会发生错误,未知的未知数。

在我上一份工作中,我们从第三方获得了唯一标识UUID的对象。 我把一个UUID->长整数查找表,并使用长整数作为我的主键,因为它是这样快的方式。

UUID体现了与全局variables相关的所有不良编码习惯,更糟糕的是,它们是超全局variables,可以分布在不同的工具箱上。

最近碰到这样一个问题,用一个确切的replace模型replace一台打印机,发现客户端软件都不能工作。