我正在尝试向 MySql 8.0.17 中的现有表添加一列。该列需要包含 UUID,我正在尝试将其设置为默认值。
这是我正在执行的语句
ALTER TABLE myTable ADD COLUMN UUID varchar(36) NOT NULL DEFAULT (UUID());
但是我收到以下错误
错误代码:1674。语句不安全,因为它使用的系统函数可能会在从站上返回不同的值。
我从其他帖子中读到,可以在表上创建触发器,但是我想知道是否可以将其直接设置为列上的默认值。
此外,使用 UUID 的二进制转换比仅使用简单的 UUID 有什么优势?
例如。
ALTER TABLE myTable ADD COLUMN UUID binary(16) NOT NULL DEFAULT (UUID_TO_BIN(UUID(), true));
感谢您的帮助。
将
UUID()
指定为默认值将不起作用,因为它不能保证在您的副本上生成相同的值。这就是为什么使用 TRIGGER 是新记录(插入)的好选择。
如果您也想更新当前记录,您可以编写更新语句
update myTable
set UUID = UUID()
您的列的类型为
binary(16)
,这意味着 UUID 数据已隐式转换为二进制。不需要使用 UUID_TO_BIN
。
编辑:
CHAR/VARCHAR 是人类可读的格式。而二进制是紧凑格式。 这意味着将 32 个字符(带分隔符的 36 个或更多)压缩为 16 位格式或恢复为人类可读的格式。
如果你不介意读取UUID,最好是使用二进制格式
将 VARCHAR 更改为 CHAR,这样您就可以使用 16 位。
老方法
ALTER TABLE myTable ADD COLUMN UUID varchar(36) NOT NULL DEFAULT (UUID());
新方法
ALTER TABLE myTable ADD COLUMN UUID BINARY(36) NOT NULL DEFAULT (UUID_TO_BIN(UUID()));
如果直接将 ALTER 命令发送到副本服务器执行(而不是在主服务器上创建包含数据的列,然后复制该信息),则会出现您遇到的错误,因为 UUID() 函数可能会在副本服务器上生成不同的唯一标识符配置中的主服务器(执行查询的位置)和副本服务器。这种不一致可能会损害数据完整性。
虽然它对于
CREATE TABLE
工作得很好,但对于 ALTER TABLE
却没有达到预期的效果。
提供的解决方案通过将流程分解为不同的
ALTER TABLE
语句来解决这个问题:
添加列:
ALTER TABLE foo ADD guid binary(16);
填充 UUID:
UPDATE foo SET guid = uuid();
设置 NOT NULL 和默认值:
ALTER TABLE foo MODIFY guid binary(16) NOT NULL DEFAULT (uuid());
此方法可确保以下几点:
UPDATE
语句将所有现有行填充为 UUID。NOT NULL
约束和默认值,保证主服务器和副本服务器之间的一致性。binary(16)
而不是 varbinary(16)
,以确保二进制 UUID 表示的固定大小为 16 字节。UPDATE
语句,此方法可能会在主服务器和副本服务器之间生成更多数据流。虽然提供的顺序效果很好,但您可以交换步骤 2 和 3:
添加默认列:
ALTER TABLE foo MODIFY guid binary(16) DEFAULT (uuid());
更新空值(如果有):
UPDATE foo SET guid = uuid() WHERE guid IS NULL;
设置非空:
ALTER TABLE foo MODIFY guid binary(16) NOT NULL;
如果您正在处理大量数据集,请考虑以较小的批次更新现有列,以最大程度地减少影响。