为 MySql 生成完全不同的 UUID
Generating completely different UUID for MySql
我在 SO 上看到过其他类似的问题,但我在这里问的问题在那里没有得到回答。
我的 table 上有一个名为 GUID
的字段,它是主键。
我希望每次插入记录时都用随机 UUID 填充此字段。
所以,我创建了这个 table:
CREATE TABLE `myTable` (
`id` int(6) NOT NULL,
`first_name` varchar(64) NOT NULL,
`last_name` varchar(64) NOT NULL,
`GUID` char(40) NOT NULL,
PRIMARY KEY(`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DELIMITER //
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `myTable`
FOR EACH ROW begin
SET new.GUID := (SELECT uuid());
END //
DELIMITER ;
我已向此 table 插入了 4 条新记录,这些是添加到条目中的 UUID:
- ae353781-9022-11ea-b775-1866daed31d4
- ae353a23-9022-11ea-b775-1866daed31d4
- ae353b4e-9022-11ea-b775-1866daed31d4
- ae353c26-9022-11ea-b775-1866daed31d4
除了 3 个数字外,这些基本上是相同的 UUID。
如何在插入新记录时生成 table 唯一的完全不同的 UUID?
为了回答您的问题,是的,guid 或 uuid 并非设计为难以预测。它只是被设计成独一无二的,这是一项非常困难的任务。
拥有像这样的大主键确实会耗尽 space,从而降低性能。
除非万不得已,否则我不会推荐它。通常人们在预先计划将数据分片到多个表中时会使用 guid 作为键。
反对这样做的另一个论点是混淆不是安全的。如果从安全角度来看存在问题,有人看到了他们不应该看到的东西,因为他们访问了 url 和 id=3
,那么如果 url 是 id=ae353c26-9022-11ea-b775-1866daed31d4
。该应用程序不应允许某人访问 id=3
,如果他们不应该能够访问它的话。
话虽如此,用于此类方案的一种解决方法是对输入进行哈希处理。
您可以使用 uuid 与行中的一些数据连接,也许还有时间戳,以及一些随机的东西和 运行 例如通过 sha1() 。它将产生一个 40 个字符的大十六进制字符串。
可能会发生碰撞,因此您可能需要检查并从中恢复。
CREATE TABLE `myTable` (
`id` int(6) NOT NULL,
`first_name` varchar(64) NOT NULL,
`last_name` varchar(64) NOT NULL,
`GUID` char(40) NOT NULL,
PRIMARY KEY(`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DELIMITER //
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `myTable`
FOR EACH ROW begin
SET new.GUID := (SELECT SHA1(CONCAT(new.first_name, RAND(), UUID(), new.last_name, NOW())));
END //
DELIMITER ;
uuid() 函数生成 UUIDv1,其定义方式相当可预测。如果您非常快速地生成一堆新值,它们只会相差几位——但它们仍然保证是唯一的。
如果你想要不可预测的值,那么你需要切换到生成UUIDv4的函数。这仅在统计上是独一无二的,但除非您在数十亿年内每秒生成数十亿个值,否则它在实践中已经足够好了。
旁白:您可能需要考虑将 UUID 存储为 BINARY(16) 以节省 space 并提高搜索效率。如果您需要在数据库中进行故障排除,可以使用生成的列来获取文本版本。
我在 SO 上看到过其他类似的问题,但我在这里问的问题在那里没有得到回答。
我的 table 上有一个名为 GUID
的字段,它是主键。
我希望每次插入记录时都用随机 UUID 填充此字段。
所以,我创建了这个 table:
CREATE TABLE `myTable` (
`id` int(6) NOT NULL,
`first_name` varchar(64) NOT NULL,
`last_name` varchar(64) NOT NULL,
`GUID` char(40) NOT NULL,
PRIMARY KEY(`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DELIMITER //
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `myTable`
FOR EACH ROW begin
SET new.GUID := (SELECT uuid());
END //
DELIMITER ;
我已向此 table 插入了 4 条新记录,这些是添加到条目中的 UUID:
- ae353781-9022-11ea-b775-1866daed31d4
- ae353a23-9022-11ea-b775-1866daed31d4
- ae353b4e-9022-11ea-b775-1866daed31d4
- ae353c26-9022-11ea-b775-1866daed31d4
除了 3 个数字外,这些基本上是相同的 UUID。
如何在插入新记录时生成 table 唯一的完全不同的 UUID?
为了回答您的问题,是的,guid 或 uuid 并非设计为难以预测。它只是被设计成独一无二的,这是一项非常困难的任务。
拥有像这样的大主键确实会耗尽 space,从而降低性能。
除非万不得已,否则我不会推荐它。通常人们在预先计划将数据分片到多个表中时会使用 guid 作为键。
反对这样做的另一个论点是混淆不是安全的。如果从安全角度来看存在问题,有人看到了他们不应该看到的东西,因为他们访问了 url 和 id=3
,那么如果 url 是 id=ae353c26-9022-11ea-b775-1866daed31d4
。该应用程序不应允许某人访问 id=3
,如果他们不应该能够访问它的话。
话虽如此,用于此类方案的一种解决方法是对输入进行哈希处理。
您可以使用 uuid 与行中的一些数据连接,也许还有时间戳,以及一些随机的东西和 运行 例如通过 sha1() 。它将产生一个 40 个字符的大十六进制字符串。
可能会发生碰撞,因此您可能需要检查并从中恢复。
CREATE TABLE `myTable` (
`id` int(6) NOT NULL,
`first_name` varchar(64) NOT NULL,
`last_name` varchar(64) NOT NULL,
`GUID` char(40) NOT NULL,
PRIMARY KEY(`GUID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DELIMITER //
CREATE TRIGGER `t_GUID` BEFORE INSERT ON `myTable`
FOR EACH ROW begin
SET new.GUID := (SELECT SHA1(CONCAT(new.first_name, RAND(), UUID(), new.last_name, NOW())));
END //
DELIMITER ;
uuid() 函数生成 UUIDv1,其定义方式相当可预测。如果您非常快速地生成一堆新值,它们只会相差几位——但它们仍然保证是唯一的。
如果你想要不可预测的值,那么你需要切换到生成UUIDv4的函数。这仅在统计上是独一无二的,但除非您在数十亿年内每秒生成数十亿个值,否则它在实践中已经足够好了。
旁白:您可能需要考虑将 UUID 存储为 BINARY(16) 以节省 space 并提高搜索效率。如果您需要在数据库中进行故障排除,可以使用生成的列来获取文本版本。