我真的不明白UUID的意义。我知道发生碰撞的可能性实际上是nil,但实际上nil几乎不可能。
有人可以举一个例子,您除了使用UUID别无选择。从我所看到的所有用途中,我可以看到没有UUID的替代设计。当然,设计可能会稍微复杂一些,但至少它不会有非零的失败概率。
对我来说,UUID闻起来像全局变量。全局变量可以通过多种方式来简化设计,但这只是懒惰的设计。
我真的不明白UUID的意义。我知道发生碰撞的可能性实际上是nil,但实际上nil几乎不可能。
有人可以举一个例子,您除了使用UUID别无选择。从我所看到的所有用途中,我可以看到没有UUID的替代设计。当然,设计可能会稍微复杂一些,但至少它不会有非零的失败概率。
对我来说,UUID闻起来像全局变量。全局变量可以通过多种方式来简化设计,但这只是懒惰的设计。
Answers:
我为Ruby编写了UUID生成器/解析器,因此我认为自己对这个主题有足够的了解。有四个主要的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空间内偶然发生。除非您接受整个Internet范围内的ID,或者在不受信任的环境中接受恶意的ID冲突的情况,否则恶意个人可能会在ID冲突的情况下做一些不好的事情,除非您不必担心。至关重要的是要理解,在大多数情况下,如果您恰好生成与我相同的版本4 UUID,则没关系。我在与您完全不同的ID空间中生成了ID。我的应用程序永远不会知道该碰撞,因此该碰撞无关紧要。坦白说,在没有恶意行为者的单个应用程序空间中,即使在版本4 UUID上,即使在
另外,2 ^ 64 * 16是256艾字节。像这样,在单个应用程序空间中有50%的ID冲突机会之前,您需要存储256艾字节的ID。
uuid.raw
将为您提供字节字符串。该hash
方法对您没有用。它用于Ruby内部的哈希表和比较操作。用于在各种UUID表示之间进行转换的所有方法均定义为类方法,并且应以开头"parse"
。
UUID买给您的东西很难做到,否则您将获得唯一的标识符,而无需咨询或与中央机构协调。没有某种托管基础结构就可以得到这样的东西的普遍问题是UUID解决的问题。
我已经读到,根据生日悖论,一旦生成2 ^ 64个UUID,发生UUID冲突的机会是50%。现在2 ^ 64是一个相当大的数字,但是发生碰撞的几率高达50%似乎太冒险了(例如,在发生碰撞的几率达5%之前,需要存在多少个UUID-即使这似乎太大了) 。
该分析存在两个问题:
UUID并不是完全随机的-UUID的主要组成部分是基于时间和/或位置的。因此,要想有真正的碰撞机会,需要从不同的UUID生成器中准确地同时生成冲突的UUID。我想说,虽然有可能同时生成多个UUID,但还有足够的其他问题(包括位置信息或随机位)使得几乎不可能在这套非常小的UUID之间发生冲突。
严格来说,UUID只需要在可能与之进行比较的其他UUID集合中是唯一的即可。如果要生成要用作数据库密钥的UUID,则在邪恶的替代宇宙中的其他地方使用相同的UUID来标识COM接口也没关系。就像如果在Alpha-Centauri上还有一个名叫“ Michael Burr”的人(或其他东西),这也不会引起混淆。
强调“合理地”或您所说的“有效地”:现实世界的工作方式就足够好。填补“实际上唯一”和“真正唯一”之间的空白所涉及的计算工作量很大。唯一性是收益递减的曲线。在那条曲线的某个点上,在仍然可以承受“足够独特”的地方之间存在一条线,然后我们非常陡峭地弯曲。增加更多唯一性的成本变得相当大。无限的唯一性具有无限的代价。
相对而言,UUID / GUID是一种生成ID的计算快速简便的方法,可以合理地认为该ID 是通用的。这在许多需要集成以前未连接的系统中的数据的系统中非常重要。例如:如果您有一个在两个不同平台上运行的内容管理系统,但是在某个时候需要将内容从一个系统导入另一个系统。您不希望ID发生更改,因此您在系统A中的数据之间的引用保持不变,但是您不希望与系统B中创建的数据发生任何冲突。UUID可以解决此问题。
创建UUID绝对不是绝对必要的。但是,有一种方便的标准,即脱机用户可以生成冲突可能性极低的密钥。
这可以帮助数据库复制解析等。
在线用户很容易为某事生成唯一密钥,而不会产生开销或冲突的可能性,但这不是UUID的目的。
无论如何,从维基百科摘录的有关碰撞可能性的词:
从这些数字来看,据估计,一个人每年被陨石击中的风险是170亿的机会,这相当于在一年内创造数十万亿个UUID并重复一次的可能性。换句话说,只有在接下来的100年中每秒生成10亿个UUID之后,才创建一个副本的可能性约为50%。
一个经典的例子是在两个数据库之间复制时。
DB(A)插入一个ID为10的记录,同时DB(B)创建一个ID为10的记录。这是冲突。
对于UUID,这将不会发生,因为它们将不匹配。(几乎可以确定)
还有一个非零的可能性,即您体内的每个粒子都会同时穿过您坐在的椅子,然后突然发现自己坐在地板上。
你担心吗?
我有一个避免UUID的方案。在某处设置服务器并拥有它,以便每当某个软件想要通用的唯一标识符时,他们都会与该服务器联系,然后服务器将其分发出去。简单!
除了存在一些实际的实际问题外,即使我们忽略了彻底的恶意。特别是,该服务器可能会从Internet的一部分发生故障或无法访问。处理服务器故障需要复制,而且很难做到这一点(请参阅Paxos算法的文献,以了解共识构建的原因)并且速度也很慢。此外,如果所有的服务器都从“网的特定部分不可达,无连接到子网的客户端将能够做任何事情,因为他们都会等待着新的ID。
因此,...使用简单的概率算法来生成它们,在地球的生命周期内不太可能发生故障,或者(拨款并)建立将成为部署PITA并经常发生故障的主要基础架构。我知道我要去哪一个。
我还没有完全谈到碰撞的可能性。我不在乎碰撞。我在乎性能。
https://dba.stackexchange.com/a/119129/33649
对于非常大的表,UUID会对性能造成损害。(200K行不是“很大”。)
当CHARCTER SET为utf8时,您的#3确实很糟糕-CHAR(36)占用108个字节!
UUID(GUID)非常“随机”。在大型表上将它们用作UNIQUE或PRIMARY键非常低效。这是因为每次插入新的UUID或通过UUID进行SELECT时,都必须在表/索引周围跳转。当表/索引太大而无法放入高速缓存(请参阅innodb_buffer_pool_size,该值必须小于RAM,通常为70%)时,“下一个” UUID可能不会被高速缓存,因此磁盘命中速度很慢。当表/索引的大小是高速缓存的20倍时,仅高速缓存1/2/5(5%)的命中数-您受I / O约束。
因此,除非任何一个都不要使用UUID
您有“小”表,或者由于从不同位置生成唯一ID(并且还没有想出另一种方法)而真正需要它们。有关UUID的更多信息:http : //mysql.rjweb.org/doc.php/uuid(它包括用于在标准36个字符的UUID和BINARY(16)之间转换的函数。)
在同一表中同时拥有UNIQUE AUTO_INCREMENT和UNIQUE UUID都是浪费。
发生INSERT时,必须检查所有唯一/主键是否重复。这两个唯一密钥都足以满足InnoDB拥有PRIMARY KEY的要求。BINARY(16)(16个字节)有点笨重(反对将其设为PK),但还不错。当您具有辅助键时,体积很重要。InnoDB默默地将PK附加到每个辅助密钥的末尾。这里的主要课程是最大程度地减少辅助键的数量,尤其是对于非常大的表。为了进行比较:INT UNSIGNED是4个字节,范围为0..4十亿。BIGINT是8个字节。
如果仅查看简单数据库应用程序的替代方法,而不必每次创建新对象之前都要查询数据库,那么您很快就会发现使用UUID可以有效地降低系统的复杂性。授予-如果您使用int密钥,则它们是32位,将存储在128位UUID的四分之一中。理所当然-UUID生成算法比简单地增加一个数字占用更多的计算能力。但谁在乎?根据指定的唯一性ID空间,管理“权限”以分配其他唯一号的开销很容易超过数量级。
在我的上一份工作中,我们从第三方获得了以UUID唯一标识的对象。我放入了UUID-> long integer查找表,并使用long integer作为我的主键,因为这样做的速度更快。
使用版本1算法,在相同的MAC地址每毫秒生成少于10个UUID的约束下,似乎不可能发生冲突
从概念上讲,UUID的原始(版本1)生成方案是将UUID版本与生成UUID的计算机的MAC地址以及自西方采用格里高利历以来的100纳秒间隔连接起来。实际上,实际算法更加复杂。有人批评这种方案“不够透明”。它既揭示了生成UUID的计算机的身份,又揭示了生成UUID的时间。
如果我误解了它的工作原理,请有人纠正我
除了必须使用需要UUID的其他人的API的情况以外,当然总会有另一种解决方案。但是这些替代方案能否解决UUID 所解决的所有问题?当您一次可以解决所有这些问题时,您是否最终会增加更多的hacks层,每层都可以解决一个不同的问题?
是的,UUID在理论上可能会发生冲突。正如其他人指出的那样,它根本不值得考虑,这很荒谬。迄今为止从未发生过,很可能永远不会发生。忘掉它。
避免冲突的最“明显”方法是让单个服务器在每个插入上生成唯一的ID,这显然会造成严重的性能问题,并且根本无法解决离线生成问题。哎呀
另一种“显而易见的”解决方案是中央机构,该机构预先分发唯一编号的块,这实际上是UUID V1通过使用生成机的MAC地址(通过IEEE OUI)执行的操作。但是确实会出现重复的MAC地址,因为每个中央机构最终都会搞砸,因此在实践中,这比UUID V4冲突更有可能。哎呀
反对使用UUID的最佳论点是它们“太大”,但是(显着)较小的方案将不可避免地无法解决最有趣的问题。UUID的大小是其在解决这些问题时有用的内在副作用。
您的问题可能还不够大,无法使用UUID提供的功能,在这种情况下,请随意使用其他功能。但是,如果您的问题出乎意料地增长(并且大多数情况都如此),您最终将在以后切换-踢自己一开始就不要使用它们。为什么要为失败而设计却又为成功而设计一样容易?