当前位置:  开发笔记 > 编程语言 > 正文

我应该如何在MySQL表中存储GUID?

如何解决《我应该如何在MySQL表中存储GUID?》经验,为你挑选了8个好方法。

我是否使用varchar(36)或有更好的方法吗?



1> thaBadDawg..:

当我问到为我的对象存储GUID的最佳方法时,我的DBA问我,为什么我需要存储16个字节,而我可以用4个字节用Integer做同样的事情.既然他把那个挑战放在我身边,我想现在是提及它的好时机.话虽如此...

如果要最佳地利用存储空间,可以将guid存储为CHAR(16)二进制文件.


因为有16个字节,你可以在不同的数据库,不同的机器上,在不同的时间生成东西,并且仍然可以无缝地合并数据:)
GUID远远优于自动增量有几个很好的理由.Jeff Atwood列出[这一个](http://www.codinghorror.com/blog/2007/03/primary-keys-ids-versus-guids.html).对我来说,使用GUID的最大好处是我的应用程序不需要数据库往返来知道实体的密钥:我可以以编程方式填充它,如果我使用自动增量字段,则无法执行此操作.这使我免于几个令人头疼的问题:使用GUID,我可以以相同的方式管理实体,无论实体是否已经持久存在,或者它是一个全新的实体.
需要回复,真正的char 16二进制文件是什么?不是char?不是二进制?我在任何mysql gui工具中都没有看到这种类型,也没有在mysql站点中看到任何文档.@BillyONeal
@nawfal:Char是数据类型.BINARY是类型的类型说明符.它唯一的作用是修改MySQL进行整理的方式.有关详细信息,请参阅http://dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html.当然,如果您的数据库编辑工具允许您这样做,您可以直接使用BINARY类型.(较旧的工具不知道二进制数据类型,但知道二进制列标志)
CHAR和BINARY字段基本相同.如果你想把它带到最基本的级别,CHAR是一个二进制字段,期望0到255的值,意图用从查找表映射的值表示所述值(在大多数情况下,现在是UTF8).BINARY字段需要相同类型的值,而无意表示查找表中的所述数据.我在4.x天里使用了CHAR(16),因为当时MySQL并不像现在这么好.

2> Brian Fisher..:

我会将它存储为char(36).


我不明白你为什么要存放```s.
@AfshinMehrabani简单,直接,易于阅读。当然,这不是必需的,但是如果存储这些多余的字节没有影响,那么这是最好的解决方案。
存储破折号可能不是一个好主意,因为它将导致更多的开销。如果要使其易于阅读,请使应用程序带有破折号。

3> KCD..:

添加到ThaBadDawg的答案,使用这些方便的函数(感谢我的一个更聪明的同事)从36长度字符串返回到16的字节数组.

DELIMITER $$

CREATE FUNCTION `GuidToBinary`(
    $Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result BINARY(16) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Data = REPLACE($Data,'-','');
        SET $Result =
            CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
                    UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
                    UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
                    UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
                    UNHEX(SUBSTRING($Data,17,16)));
    END IF;
    RETURN $Result;
END

$$

CREATE FUNCTION `ToGuid`(
    $Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result CHAR(36) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Result =
            CONCAT(
                HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
                HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-', 
                HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
                HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
                HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
    END IF;
    RETURN $Result;
END
$$

CHAR(16)实际上是一个BINARY(16),选择你喜欢的味道

要更好地遵循代码,请参考下面给出数字排序GUID的示例.(非法字符用于说明目的 - 每个字符都有一个唯一的字符.)这些函数将转换字节顺序,以实现高级索引聚类的位顺序.重新排序的guid显示在示例下方.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW

删除了破折号:

123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW


好奇的是,这些函数优于UNHEX(REPLACE(UUID(),' - ','')),因为它按照在聚簇索引中表现更好的顺序排列位.

4> Learning..:

char(36)将是一个不错的选择.此外,还可以使用MySQL的UUID()函数,该函数返回36个字符的文本格式(带连字符的十六进制),可用于从db中检索此类ID.



5> candu..:

"更好"取决于你所优化的内容.

您对存储大小/性能与易于开发的关注程度有多大?更重要的是 - 你生成足够的GUID,或者经常提取它们,重要吗?

如果答案是"否",char(36)那就足够了,它使存储/获取GUID变得简单.否则,这binary(16)是合理的,但你必须依靠MySQL和/或你选择的编程语言来转换来自通常的字符串表示.


如果你托管软件(例如一个网页)并且不在客户端销售/安装,你总是可以从char(36)开始,以便在软件的早期阶段轻松开发,并变异为更紧凑格式随着系统使用的增长而开始需要优化.

6> Onkar Janwa..:

二进制(16)会好,比使用varchar(32)更好.



7> bigh_29..:

应调整KCD发布的GuidToBinary例程,以考虑GUID字符串中时间戳的位布局.如果字符串表示版本1 UUID,就像uuid()mysql例程返回的那样,则时间组件嵌入字母1-G,不包括D.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC     = middle 2 timestamp bytes in big endian
D        = 1 to signify a version 1 UUID
EFG      = most significant 12 bits of the timestamp in big endian

转换为二进制时,索引的最佳顺序为:EFG9ABC12345678D +其余部分.

您不希望将12345678交换为78563412,因为big endian已经产生了最佳的二进制索引字节顺序.但是,您确实希望在较低字节前面移动最重要的字节.因此,EFG先行,然后是中间位和低位.在一分钟内使用uuid()生成十几个UUID,你应该看看这个顺序如何产生正确的排名.

select uuid(), 0
union 
select uuid(), sleep(.001)
union 
select uuid(), sleep(.010)
union 
select uuid(), sleep(.100)
union 
select uuid(), sleep(1)
union 
select uuid(), sleep(10)
union
select uuid(), 0;

/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6 

前两个UUID是最接近时间生成的.它们仅在第一个块的最后3个半字节中变化.这些是时间戳的最低有效位,这意味着当我们将其转换为可索引的字节数组时,我们希望将它们推到右侧.作为一个反例,最后一个ID是最新的,但KCD的交换算法会将它放在第3个ID之前(直流前3e,第一个块的最后一个字节).

索引的正确顺序是:

1e497556eec5eb6... 
1e497556eec5f10... 
1e497556eec8ddc... 
1e497556eee30d0... 
1e497556efda038... 
1e497556f9641bf... 
1e49755758c3e3e... 

有关支持信息,请参阅此文章:http://mysql.rjweb.org/doc.php/uuid

***请注意,我没有从时间戳的高12位分割版本半字节.这是你的例子中的D半字节.我把它扔在前面.所以我的二进制序列最终成为DEFG9ABC等等.这意味着我所有索引的UUID都以相同的半字节开头.文章做了同样的事情.



8> sleepycal..:

对于那些刚刚陷入困境的人来说,根据Percona的研究,现在有了更好的选择.

它包括重新组织UUID块以获得最佳索引,然后转换为二进制以减少存储.

阅读完整的文章在这里


来自MariaDB的更新文章应该回答你的问题https://mariadb.com/kb/en/mariadb/guiduuid-performance/
推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有