MySQL中的UUID性能?

Pat*_*ody 77 mysql performance uuid innodb sequence

我们正在考虑使用UUID值作为MySQL数据库的主键.插入的数据是从数十台,数百台甚至数千台远程计算机生成的,并以每秒100-40,000次插入的速率插入,我们永远不会进行任何更新.

在我们开始剔除数据之前,数据库本身通常会达到大约50M的记录,因此不是一个庞大的数据库,但也不是很小.我们也计划在InnoDB上运行,但如果我们正在做的事情有更好的引擎,我们愿意改变它.

我们已准备好使用Java的Type 4 UUID,但在测试中已经看到了一些奇怪的行为.首先,我们将存储为varchar(36),现在我意识到我们最好使用二进制(16) - 尽管我不确定会有多好.

更大的问题是:当我们拥有50M记录时,这个随机数据对索引的影响有多大?如果我们使用例如最左边的位被加时间戳的1型UUID,我们会更好吗?或者我们应该完全抛弃UUID并考虑auto_increment主键?

我正在寻找关于不同类型的UUID在MySQL中作为索引/主键存储时的性能的一般想法/提示.谢谢!

Kat*_*uiz 73

在我的工作中,我们使用UUID作为PK.我从经验中可以告诉你的是,不要将它们用作PK(顺便提一下SQL Server).

当你记录的记录少于1000时,它就是其中之一;没问题,但是当你拥有数百万时,这是你能做的最糟糕的事情.为什么?因为UUID不是顺序的,所以每次插入新记录时MSSQL都需要查看正确的页面以插入记录,然后插入记录.这个真正丑陋的结果是页面最终都以不同的大小结束,最终会碎片化,所以现在我们必须定期进行去碎片化.

当你使用自动增量时,MSSQL总会转到最后一页,你最终得到同样大小的页面(理论上),所以选择那些记录的性能要好得多(也因为INSERT不会阻塞表/页面)太长).

但是,使用UUID作为PK的一大优势是,如果我们有DB集群,合并时就不会有冲突.

我建议使用以下模型:1.PK INT Identity 2.附加列自动生成为UUID.

这样,合并过程是可能的(UUID将是您的REAL键,而PK只是暂时性的,可以提供良好的性能).

注意:最好的解决方案是使用NEWSEQUENTIALID(就像我在评论中所说的那样),但是对于没有太多时间重构的遗留应用程序(更糟糕的是,不控制所有插入),这是不可能的.但实际上到2017年,我会说这里最好的解决方案是NEWSEQUENTIALID或者用NHibernate做Guid.Comb.

希望这可以帮助

  • 我一直在想的是,这对于亲子关系来说可能效果不佳.在这种情况下,我认为你必须在子表中添加:parent-pk,parent-guid.否则可能会丢失数据库之间的引用.我没有想太多,也没有做过任何例子,但这可能是必要的 (3认同)
  • 在SQL Server中@KatLimRuiz你可以使用NEWSEQUENTIALID()http://technet.microsoft.com/en-us/library/ms189786.aspx来避免性能问题 (3认同)

Dan*_*umb 32

UUID是通用唯一ID.这是你应该在这里考虑的普遍部分.

真的需要这些ID是普遍独一无二的吗?如果是这样,那么UUID可能是您唯一的选择.

我强烈建议,如果你使用的UUID,您将它们保存为一个数字,而不是作为一个字符串.如果您有50M +记录,那么节省存储空间将提高您的性能(虽然我不能说多少).

如果您的ID不需要是普遍唯一的,那么我认为您可以做得更好,只需使用auto_increment,这可以保证ID在表中是唯一的(因为每次都会增加值)

  • 我们最终对真实数据进行了一些基准测试,并且没有按键的GUID相当快,带有键的GUID非常糟糕(即使存储为BINARY),并且int w/AUTO_COMPLETE是最快的.我认为在我们的情况下,我们确实错过了树木中的森林,因为与存储更多数据的成本相比,序列生成似乎无关紧要+由于GUID的随机性而具有非常糟糕的BTREE (12认同)
  • 严格来说,UUID*普遍*独特,这意味着它永远不会出现在世界其他任何地方.如果您公开分享数据,则只需要这样做.至于将UUID存储为数字,我的意思并不是"二进制"格式.我的意思是128位数字,而不是288位字符串.例如,ASCII中的'hello'一词是'68 65 6C 6C 6F`,即448,378,203,247.存储字符串'68656C6C6F'需要10个字节.数字448,378,203,247只需要5.总而言之,除非你*真的*需要UUID中的第一个U,否则你不能比`auto_increment更好 (4认同)
  • 有趣的一点; 这将并行化密钥的生成.我相信这会提高密钥生成的性能.但是,如果使用VARCHAR存储UUID,则选择INSERT性能优于SELECT性能.您绝对应该选择VARBINARY进行存储以确保SELECT性能.额外的步骤*可能*影响INSERT性能,但您将获得SELECT性能提升的回报. (2认同)

Kyl*_*ndo 25

需要考虑的是,自动增量是一次生成一个,并且无法使用并行解决方案来解决.使用UUID的斗争最终取决于你想要实现的目标与你可能牺牲的目标.

关于表现,简要说明:

像上面这样的UUID是36个字符长,包括破折号.如果存储此VARCHAR(36),则会显着降低比较性能.这是你的主键,你不希望它变慢.

在它的位级别,UUID是128位,这意味着它将适合16个字节,注意这不是人类可读的,但它将保持低存储,并且只比32位int大4倍,或2大于64位int的时间.我将使用VARBINARY(16)从理论上讲,这可以在没有大量开销的情况下工作.

我建议阅读以下两篇文章:

我估计两者之间,他们回答你的问题.

  • 实际上,我在发布这个问题之前已经阅读了这两篇文章,但我仍然没有在这里得到一个好的答案.例如,既没有谈论类型1与类型4 UUIDS :( (2认同)

小智 5

我倾向于避免使用UUID,因为存储起来很痛苦并且使用它作为主键是一种痛苦,但是有一些优点.主要的是它们是独一无二的.

我通常使用双键字段解决问题并避免使用UUID.

收集器=独特的机器分配

ID =收集器收集的记录(auto_inc字段)

这给了我两件事.自动加入字段的速度和数据的唯一性在收集并组合在一起后存储在中心位置.我也知道在浏览收集数据时,这通常对我的需求非常重要.

我在为客户决定使用UUID处理其他数据集时遇到了很多情况,但是仍然有一个用于收集数据的字段,这实际上是浪费精力.只需使用两个(或更多,如果需要)字段作为您的密钥真的有帮助.

我刚刚看到使用UUID的太多性能命中.他们觉得自己像个骗子......