MySQL主键:UUID / GUID与BIGINT时间戳+随机数

问题描述

| tl; dr:如果我不想处理UUID,将{unixtimestamp} {randomdigits}的行ID(例如1308022796123456)分配为BIGINT是一个好主意吗? 只是想知道是否有人对跨多个服务器分配给数据库记录的ID / PRIMARY KEY有任何性能或其他技术上的考虑/限制。 我的PHP + MysqL应用程序在多个服务器上运行,并且数据需要能够合并。因此,我已经不再使用识别行的标准顺序/ auto_increment整数方法。 我对解决方案的研究使我想到了使用UUID / GUID的概念。但是,需要更改我的代码以处理在MysqL中将UUID字符串转换为二进制值的需求似乎有些麻烦/工作。由于存储和性能的原因,我不想将UUID存储为VARCHAR。 存储在二进制列中的UUID的另一个可能的烦人之处是,当在PHPMyAdmin中查看数据时,行ID并不明显-尽管我可能是错的-但是无论如何,直数总体上看起来要简单得多,并且在整个过程中都是通用的无需转换的任何种类的数据库系统。 作为中间立场,我想到了将我的ID列设置为BIGINT的想法,并使用当前的unix时间戳和6个随机数字来分配ID。假设我的随机数大约为123456,今天生成的ID为:1308022796123456 对于在同一秒内创建的行,每千万分之一的发生冲突的可能性对我来说很好。我没有快速进行任何大规模的行创建。 我读过的关于随机生成的UUID的一个问题是,它们对于索引不利,因为值不是连续的(它们分布在各处)。 MysqL中的UUID()函数通过根据当前时间戳生成UUID的第一部分来解决此问题。因此,我已经复制了在BIGINT开始时使用unix时间戳的想法。我的索引会变慢吗? 我的BIGINT想法的优点: 给我UUID的多服务器/合并优势 几乎不需要更改我的应用程序代码(所有内容都已编程为处理ID的整数) UUID的一半存储(8字节vs 16字节) 缺点: ??? -如果您能想到的话,请告诉我。 一些后续问题可以解决: 最后应该使用少于或少于6个随机数字吗?会对索引性能产生影响吗? 这些方法之一是否是\“ randomer \” ?:使PHP生成6位数字并将它们连接在一起-VS-使PHP生成1-999999范围内的数字,然后进行零填充以确保6位数字。 感谢您的提示。抱歉,文字墙。     

解决方法

        我的职业生涯遇到了这个问题。我们使用时间戳+随机数,并在我们的应用程序扩展时遇到了严重的问题(更多的客户端,更多的服务器,更多的请求)。当然,我们(愚蠢地)仅使用4位数字,然后更改为6位数字,但是您会惊讶地发现错误仍然经常发生。 在足够长的时间内,可以确保您得到重复的密钥错误。我们的应用程序是关键任务,因此即使由于固有的随机行为而导致失败的最小机会也是不可接受的。我们开始使用UUID来避免此问题,并仔细管理了它们的创建。 使用UUID,索引的大小将增加,索引的增加将导致性能下降(也许不明显,但仍然较差)。但是MySQL支持本机UUID类型(切勿使用varchar作为主键!!),甚至比bigint都可以高效地处理索引,搜索等。索引的最大性能损失几乎总是被索引的行数,而不是被索引项目的大小(除非您要在长文本或类似的东西上进行索引)。 回答您的问题:如果您不打算大幅度扩展应用程序/服务,Bigint(带有随机数)将是可以的。如果您的代码可以在不做太多更改的情况下处理更改,并且如果发生重复的键错误,则您的应用程序也不会爆炸,请继续使用它。否则,咬住子弹,然后选择更实质的选择。 您以后总是可以实施更大的更改,例如切换到完全不同的后端(我们现在面对的是...:P)     ,您可以手动更改自动编号的起始号码。
ALTER TABLE foo AUTO_INCREMENT = ####
一个无符号的int最多可以存储4,294,967,295,可向下舍入为4,290,000,000。 服务器的序列号使用前3位数字,行ID使用最后7位数字。 这样一来,您最多可以拥有430台服务器(包括000台服务器),每台服务器最多可以有1000万个ID。 因此,对于172号服务器,您可以手动将自动编号更改为从1,720,000开始,然后让其顺序分配ID。 如果您认为可能有更多服务器,但每台服务器的ID较少,则将其调整为每台服务器4位数字,并为ID设置6位(即最多100万个ID)。 您也可以使用二进制数字而不是十进制数字来分割数字(每个服务器大概10个二进制数字,ID为22。因此,例如,服务器76起始于2 ^ 22 * 76 = 318,767,104,结束于322,961,407)。 因此,您甚至不需要明确地分开。用4,295除以您认为将拥有的最大服务器数量,这就是您的间距。 如果您认为需要更多的标识符,则可以使用bigint,但这是一个非常大的数目。     ,        使用GUID作为唯一索引,还可以计算GUID的64位(BIGINT)哈希,将其存储在单独的NOT UNIQUE列中,并为其建立索引。要进行检索,请查询两列的匹配项-64位索引应使此方法有效。 这样做的好处是哈希: 一种。不必唯一。 b。可能分布均匀。 代价:额外的8字节列及其索引。     ,        如果要使用时间戳方法,请执行以下操作: 给每个服务器一个编号,在该编号后附加正在执行插入操作的应用程序的进程ID(或线程ID)(在PHP中,该编号为getmypid()),然后在该附加后该进程已经运行了多长时间/激活(在PHP中是getrusage()),最后在每次脚本调用开始时添加一个从0开始的计数器(即,同一脚本中的每个插入都向其中添加一个)。 另外,您不需要存储完整的unix时间戳-这些数字中的大多数用于表示它是2011年而不是1970年。因此,如果您无法获得一个数字来表示该过程持续了多长时间,活着,然后至少减去代表今天的固定时间戳-这样您就需要少得多的数字。