gpt4 book ai didi

MySQL UUID 函数用作函数参数时会产生相同的值

转载 作者:行者123 更新时间:2023-12-03 01:59:14 25 4
gpt4 key购买 nike

UUID() 函数每次调用时都会产生不同的值,正如我所期望的那样:

SELECT UUID() from INFORMATION_SCHEMA.TABLES LIMIT 3;

3bb7d468-f9c5-11e9-8349-d05099466715
3bb7d482-f9c5-11e9-8349-d05099466715
3bb7d492-f9c5-11e9-8349-d05099466715

但是,一旦我们在 REPLACE() 函数中使用它,它就会开始产生相同的值:

SELECT REPLACE(UUID(),'-','-') from INFORMATION_SCHEMA.TABLES LIMIT 3;
e0f2d47a-f9c5-11e9-8349-d05099466715
e0f2d47a-f9c5-11e9-8349-d05099466715
e0f2d47a-f9c5-11e9-8349-d05099466715

这“破坏”了像这样的 Insert From Select 语句,我们希望每个插入的行都有一个唯一的值:

INSERT INTO MyTable (uid, tableName) -- uid is binary(16)
SELECT UNHEX(REPLACE(UUID(),'-','')), TABLE_NAME from INFORMATION_SCHEMA.TABLES;

请注意,为了方便起见,我使用信息模式的表列表。这应该不重要,但对于那些好奇的人来说,我们的 PK 是二进制(16)形式的 UUID。我无法改变这一点;请不要关注这一点。

UUID() 函数是非确定性的,而 REPLACE() 函数是确定性的。我本以为 UUID() 函数的非确定性特征会导致 REPLACE() 函数的行为就好像它对每一行都有不同的参数,但是假设 UUID() 恒定,数据库引擎似乎过度优化。

我还使用另一个非确定性函数 RAND() 测试了此行为,在本例中,REPLACE() 函数按我们的预期工作!

SELECT REPLACE(RAND(),' ',' ') from INFORMATION_SCHEMA.TABLES LIMIT 3;
0.911571646026868
0.626416072832808
0.6977608461843439

问题:

有没有办法执行“从选择插入”并在选择中每行生成一个二进制 16 形式的唯一 UUID?

为什么会发生这种情况?这是一个错误吗?

<小时/>

更新

我在本地使用5.7.27:

mysql 版本 14.14 Distrib 5.7.27,适用于 Linux (x86_64)

但这最终将部署到 AWS RDS 实例。哈哈...Terraform(脚本化部署)使用引擎版本 5.7.16 启动 AWS RDS 实例。

在 AWS 控制台中,我看到对版本 5.7.26(5.7 风格)和 8.0.16(8.0 风格)的支持。我将讨论升级已部署的引擎版本。我很乐意将 PK 列定义更改为 @Schwern 建议的默认值。

<小时/>

解决办法

在我让其他人同意版本更改之前,我将继续使用临时表作为生成的 id 值的中间存储。

CREATE TEMPORARY TABLE GeneratedIds (
generatedId varchar(36) NOT NULL,
tableName text NOT NULL
);
INSERT INTO GeneratedIds (generatedId, tableName)
SELECT UUID(), TABLE_NAME from INFORMATION_SCHEMA.TABLES;

INSERT INTO MyTable (uid, tableName) -- uid is binary(16)
SELECT UNHEX(REPLACE(generatedId,'-','')), tableName FROM GeneratedIds;

DROP TABLE GeneratedIds;

这不是很优雅,但确实有效。就我而言,我正在一个 sql 迁移文件中工作,在该文件中我可以以一种内聚的方式将这种 sql 序列串在一起。我不建议在代码中这样做;闻起来很臭。

<小时/>

结论

这确实是 MySQL 中的一个错误。我快速搜索了他们的错误数据库,但没有找到任何提及。不管怎样,上面的 SQL 语句说明了这个缺陷,并且 @Schwern 和我已经表明这个 bug 已在版本 5.7.27(确切地说)和版本 8.0.16(可能都是 8..)中得到修复,仅测试了 8.0.16 和 8.0.18)。

8.0.16版本测试:

Server version: 8.0.16 MySQL Community Server - GPL

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT REPLACE(UUID(),'-','-') from INFORMATION_SCHEMA.TABLES LIMIT 3;
+--------------------------------------+
| REPLACE(UUID(),'-','-') |
+--------------------------------------+
| 96f9205a-fdc6-11e9-87de-d05099466715 |
| 96f920f9-fdc6-11e9-87de-d05099466715 |
| 96f9213e-fdc6-11e9-87de-d05099466715 |
+--------------------------------------+
3 rows in set (0.00 sec)

最佳答案

MySQL 5.6.46 , 5.7.28 ,也不是 8.0.18似乎没有这个问题。如果可以的话升级。

升级的好处之一是您现在可以使用函数作为列默认值。这允许您将 UUID 设置为主键的默认值,从而避免此问题和许多其他问题。您还可以使用uuid_to_binbin_to_uuid .

create table MyTable (
uid binary(16) primary key default(uuid_to_bin(uuid())),
tableName text not null
);

INSERT INTO MyTable (tableName)
SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES;

如果无法升级,可以use a trigger to set the default primary key as in this answer .

关于MySQL UUID 函数用作函数参数时会产生相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58600623/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com