如果你希望完全匹配,请使用VARCHAR(36)
,或者使用VARCHAR(255)
,因为它们具有相同的存储成本。这里没有必要关注字节数。
请注意,VARCHAR
字段是可变长度的,因此存储成本与其中实际包含的数据量成比例,而不是可能包含的数据量。
将其存储为BINARY
非常麻烦,这些值无法打印,并且在运行查询时可能显示为垃圾。很少有理由使用字面二进制表示法。人可读的值可以复制粘贴并轻松处理。
其他一些平台(如Postgres)有一个正确的UUID列,它以更紧凑的格式存储,同时以人类可读的方式显示,因此可以同时使用这两种方法的最佳方式。
问题是关于在MySQL中存储UUID。
从mySQL 8.0版开始,您可以使用binary(16)
以及通过UUID_TO_BIN/BIN_TO_UUID
函数的自动转换:
https://mysqlserverteam.com/mysql-8-0-uuid-support/
请注意,mySQL还有一种快速生成UUID作为主键的方法:
INSERT INTO t VALUES(UUID_TO_BIN(UUID(), true))
UUID_TO_BIN/BIN_TO_UUID
适用于v4 UUID(与版本无关)。UUID()
生成“小于”v1 UUID:https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid - Karsten R.CHAR(36)
,与VARCHAR(36)
相比,每行可节省1个字节。uuid CHAR(36) CHARACTER SET ascii
BINARY(16)
,存储可读字符使用的存储空间超过了两倍,意味着更大的索引和更慢的查找速度。HEX()
和x'deadbeef01'
字面值将会是您的朋友。function guidv4($prettify = false)
{
static $native = function_exists('random_bytes');
$data = $native ? random_bytes(16) : openssl_random_pseudo_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
if ($prettify) {
return guid_pretty($data);
}
return $data;
}
function guid_pretty($data)
{
return strlen($data) == 16 ?
vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)) :
false;
}
function guid_ugly($data)
{
$data = preg_replace('/[^[:xdigit:]]+/', '', $data);
return strlen($data) == 32 ? hex2bin($data) : false;
}
如果您只需要在读取数据库时使列变得漂亮,那么以下语句就足够了:
ALTER TABLE test
ADD uuid_pretty CHAR(36) GENERATED ALWAYS AS (
CONCAT_WS(
'-',
LEFT(HEX(uuid_ugly), 8),
SUBSTR(HEX(uuid_ugly), 9, 4),
SUBSTR(HEX(uuid_ugly), 13, 4),
SUBSTR(HEX(uuid_ugly), 17, 4),
RIGHT(HEX(uuid_ugly), 12)
)
) VIRTUAL;
对我来说,在MySQL 8.0.26中这可行如魔法一般。
create table t (
uuid BINARY(16) default (UUID_TO_BIN(UUID())),
)
查询时可使用以下方法
select BIN_TO_UUID(uuid) uuid from t;
# uuid
'8c45583a-0e1f-11ec-804d-005056219395'
UUID()
函数不会生成UUID v4,因此默认情况下无法使用。但存储看起来还不错。 - Stephen RBINARY(16)
或两个BIGINT UNSIGNED
。Timestamp | Machine Identifier | Counter
DECIMAL(28, 0)
或CHAR(16)
(确保使用二进制排序规则和ASCII字符集)。 - TimoINSERT INTO table (UUID) VALUES
(UNHEX(REPLACE(UUID(), "-","")))
这是一个相当古老的帖子,但仍然相关,并经常出现在搜索结果中,因此我将添加我的答案。由于您已经必须在查询中使用触发器或自己的UUID()调用,因此这里有一对函数,我使用它们将UUID保留为文本以便在数据库中轻松查看,但将其占用空间从36减少到24个字符。(节省33%)
delimiter //
DROP FUNCTION IF EXISTS `base64_uuid`//
DROP FUNCTION IF EXISTS `uuid_from_base64`//
CREATE definer='root'@'localhost' FUNCTION base64_uuid() RETURNS varchar(24)
DETERMINISTIC
BEGIN
/* converting INTO base 64 is easy, just turn the uuid into binary and base64 encode */
return to_base64(unhex(replace(uuid(),'-','')));
END//
CREATE definer='root'@'localhost' FUNCTION uuid_from_base64(base64_uuid varchar(24)) RETURNS varchar(36)
DETERMINISTIC
BEGIN
/* Getting the uuid back from the base 64 version requires a little more work as we need to put the dashes back */
set @hex = hex(from_base64(base64_uuid));
return lower(concat(substring(@hex,1,8),'-',substring(@hex,9,4),'-',substring(@hex,13,4),'-',substring(@hex,17,4),'-',substring(@hex,-12)));
END//
UUID()
函数,因此您无需使用 PHP 来生成 UUID。您可以删除横线并将十六进制数字保存为binary(16)
。如果您通过触发器执行此操作,则应使用SELECT UNHEX(REPLACE(UUID(), '-', ''));
,如果需要索引,则将其设置为unique
,从而获得利润。 - N.B.random_bytes
)和令牌无法被获取/重复(即使用SSL,使令牌失效)。其他部分不那么重要(甚至包括获取参数)。 - pvg