在MySQL中的UUID性能?
我们正在考虑使用UUID值作为MySQL数据库的主键。 插入的数据是从数十,数百或甚至数千个远程计算机中生成的,并且以每秒100至40,000个插入的速率插入,我们将不会做任何更新。
在我们开始剔除数据之前,数据库本身通常会达到大约5千万条logging,所以不是一个庞大的数据库,但也不是很小。 我们也计划在InnoDB上运行,尽pipe如果我们正在做的事情有一个更好的引擎,我们可以改变。
我们已经准备好使用Java的Type 4 UUID了,但在testing中已经看到了一些奇怪的行为。 首先,我们将存储为varchar(36),现在我们意识到使用二进制(16)会更好 – 尽pipe我不确定多less更好。
更大的问题是:当我们有50M的logging时,这个随机数据有多糟糕? 如果我们使用例如最左边的比特是时间戳的types1UUID,我们会更好吗? 或者,也许我们应该完全抛弃UUID并考虑auto_increment主键?
我正在寻找关于不同types的UUID的性能的一般想法/技巧,当他们被存储为一个索引/主键在MySQL中。 谢谢!
UUID是通用唯一ID。 这是你应该在这里考虑的普遍的部分。
你真的需要这些ID是普遍唯一的吗? 如果是这样,那么UUID可能是你唯一的select。
我强烈build议,如果您使用UUID,则将它们存储为数字而不是string。 如果你有50M +的logging,那么在存储空间上的节省将提高你的performance(尽pipe我不能说多less)。
如果你的ID不需要是全局唯一的,那么我不认为你可以做得更好,那么只需使用auto_increment,这将保证ID在表中是唯一的(因为这个值每次都会增加)
在我的工作中,我们使用UUID作为PK。 我可以告诉你的经验是不要使用它们作为PK(顺便说一下SQL Server)。
这是其中一件事情,当你有不到1000条logging的时候,没关系,但是当你有数百万的时候,这是你能做的最糟糕的事情。 为什么? 由于UUID不是顺序的,因此每次插入新logging时,MSSQL都需要查看正确的页面以将logging插入,然后插入logging。 这个真正丑陋的结果就是页面大小不一样,最终分散了,所以现在我们必须定期去除碎片。
当你使用一个自动增量时,MSSQL将会一直到最后一页,并且最终会得到相同大小的页面(理论上),所以select这些logging的性能要好得多(因为INSERT不会阻止表/页面太长)。
然而,使用UUID作为PK的最大优点是,如果我们有数据库的簇,合并时不会有冲突。
我会推荐以下模型:1. PK INT标识2.附加列自动生成为UUID。
这样,合并过程是可能的(UUID将是你的真正的关键,而PK将只是暂时的东西,让你有良好的performance)。
注意:最好的解决scheme是使用NEWSEQUENTIALID(就像我在评论中所说的那样),但对于没有太多时间重构的遗留应用程序(甚至更糟的是,不控制所有插入),这是不可能的。 但实际上到2017年,我会说这里最好的解决scheme是NEWSEQUENTIALID或与NHibernate做Guid.Comb。
希望这可以帮助
需要考虑的一点是,自动增量一次只生成一个,不能使用并行解决scheme解决。 使用UUID的斗争最终归结为你想要实现的目标,而不是你可能牺牲的目标。
在performance上, 简单地说 :
像上面那样的UUID是36个字符,包括破折号。 如果你存储这个VARCHAR(36),你会大大降低比较性能。 这是你的主要关键,你不希望它变慢。
在它的比特级别,UUID是128位,这意味着它将适合16个字节,注意这不是人类可读的,但是它将保持低存储,并且只比32位int大4倍,或者2比64位整数大。 我将使用VARBINARY(16)理论上,这可以在没有很多开销的情况下工作。
我build议阅读以下两个职位:
- 布赖恩“克罗”阿克尔的闲置思想 – 神话,GUID与自动增量
- 要UUID还是不要UUID?
我估计两者之间,他们回答你的问题。
我倾向于避免UUID只是因为它是一个痛苦的存储和使用作为主键的痛苦,但有优势。 主要的是它们是独特的。
我通常通过使用双键字段来解决问题并避免UUID。
COLLECTOR =独特的分配给一台机器
ID =由收集器收集的logging(auto_inc字段)
这给了我两件事。 自动增加字段的速度和数据的唯一性在收集并分组在一起之后存储在中央位置。 在浏览收集的数据的同时,我也知道这通常对我的需求非常重要。
在处理客户的其他数据时,我已经看到了很多情况,他们决定使用UUID,但是仍然有一个收集数据的地方,这实在是浪费精力。 只要使用两个(或更多,如果需要)领域作为你的关键确实有帮助。
我刚刚看到使用UUID的性能命中太多。 他们觉得自己像个骗子
为每个插入集中生成唯一的密钥,而不是为每个服务器分配密钥块? 当他们用完了密钥,他们可以请求一个新的块。 然后,通过连接每个插件来解决开销问题。
Keyserver维护下一个可用的ID
- 服务器1请求ID块。
- Keyserver返回(1,1000)
服务器1可以插入1000条logging,直到它需要请求一个新的块 - 服务器2请求索引块。
- Keyserver返回(1001,2000)
- 等等…
你可以想出一个更复杂的版本,其中服务器可以请求所需密钥的数量,或者将未使用的块返回给密钥服务器,这当然需要维护已使用/未使用块的映射。
我将以事务方式为每个服务器分配一个数字ID。 然后,插入的每条logging都会自动增加自己的计数器。 ServerID和RecordID的组合将是唯一的。 ServerID字段可以被索引,并且基于ServerID的未来select性能(如果需要)可能会好得多。
那么一些手工制作的UID呢? 为每个成千上万的服务器分配一个ID并使主键成为自动增量的组合键,MachineID ???
由于主键是分散生成的,因此您无权select使用auto_increment。
如果不需要隐藏远程机器的身份,请使用Type 1 UUID而不是UUID。 它们更容易生成,至less不会伤害数据库的性能。
varchar(char,really)和binary是一样的:它只能帮助你解决问题。 这真的很重要,多lessperformance提高了?