首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MySQL UUID函数用作函数参数时产生相同的值。

问MySQL UUID函数用作函数参数时产生相同的值。
EN

Stack Overflow用户
提问于 2019-10-29 02:10:26
回答 1查看 3.3K关注 0票数 15

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

代码语言:javascript
复制
SELECT UUID() from INFORMATION_SCHEMA.TABLES LIMIT 3;

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

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

代码语言:javascript
复制
SELECT REPLACE(UUID(),'-','-') from INFORMATION_SCHEMA.TABLES LIMIT 3;
e0f2d47a-f9c5-11e9-8349-d05099466715
e0f2d47a-f9c5-11e9-8349-d05099466715
e0f2d47a-f9c5-11e9-8349-d05099466715

在这样的Select语句中,我们期望插入的每一行都有一个唯一的值:

代码语言:javascript
复制
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()函数的行为就好像它对每一行都有不同的参数一样,但是似乎DB引擎通过假设UUID()是常数来进行优化。

我还用另一个非确定性函数RAND()测试了这种行为,在本例中,REPLACE()函数如我们所期望的那样工作!

代码语言:javascript
复制
SELECT REPLACE(RAND(),' ',' ') from INFORMATION_SCHEMA.TABLES LIMIT 3;
0.911571646026868
0.626416072832808
0.6977608461843439

问题

是否有方法执行"Insert From Select“,并在select中的每一行生成二进制16格式的唯一UUID?

为什么会发生这种情况?这是个虫子吗?

更新

我在当地使用5.7.27:

mysql Ver 14.14 Distrib 5.7.27, for Linux (x86_64)

但这将最终部署到AWS RDS实例中。哈哈..。Terraform (脚本部署)使用5.7.16引擎版本编制了一个AWS RDS实例。

在AWS控制台中,我看到了5.7.26版( 5.7版)和8.0.16版( 8.0版)的支持。我将讨论如何升级已部署的引擎版本。如@Schwern所建议的,我希望将PK列定义更改为默认值。

围绕着工作

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

代码语言:javascript
复制
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中的一个bug,,我快速搜索了他们的bug DB,但是我没有发现提到它。不管怎么说,上面的SQL语句说明了这个缺陷,@Schwern和我已经证明这个错误已经在5.7.27版本(确切地)和8.0.16版本(可能所有的8..,只测试了8.0.16和8.0.18)中得到了修复。

8.0.16版本测试:

代码语言:javascript
复制
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)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-29 03:27:19

MySQL 5.6.46、5.7.28和8.0.18似乎没有这个问题。如果可以的话升级。

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

代码语言:javascript
复制
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;

如果你不能升级,你可以使用触发器设置默认主键,如下所示。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58600623

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档