4 anos atrás, respondi uma pergunta no SO , "como definir um UUID para cada linha em massa".
Eu respondi, depois de tentar,
UPDATE table SET uuidcol = UUID();
Funcionou para mim, mas cerca de metade (ao que parece) das pessoas relatam que não funciona, dizendo que o ID é idêntico em todas as linhas.
Então, hoje, tentei novamente, descartando a cada vez a coluna e criando uma nova com um novo tipo, como
text, char(36), varchar(36)
e funcionou novamente, criando um UUID exclusivo por linha, a cada vez.
O que poderia fazer que não funcione para outras pessoas?
O motor por exemplo? (usando InnoDB no MySQL 5.7)
editar
Fez outro teste por
- criando uma tabela simples
t
deuu varchar(36)
- inserindo 10.000.000 de linhas
uu
comnull
- fiz o
UPDATE t SET uu=UUID();
e todas as linhas de 10 milhões têm um UUID diferente e exclusivo .
Estou tendo exatamente esse mesmo problema agora.
Eu escrevi um exemplo de aplicativo java para demonstrar o problema:
MariaDBTestUUID.java:
A versão da biblioteca cliente é definida aqui:
build.gradle:
Para executar o aplicativo de teste, basta:
1 - conecte-se a cada um dos BDs e execute as seguintes consultas:
2 - substitua as informações de conexão mascaradas por motivos de segurança e execute-as em cada um dos BDs.
3 - defina a versão do cliente mariadb para usar no teste no build.gradle
4 - execute main()
Se a saída mostrar 3 para cada uma das consultas distintas, a instrução de atualização criou valores distintos em cada coluna. Se mostrar 1, a atualização definirá o mesmo valor para todas as linhas dessa coluna. Todas as consultas devem retornar 3.
O que eu vi, para todos os DBs:
Então, minhas descobertas até agora:
Tudo funcionou sem problemas (todas as colunas em cada linha foram definidas com valores distintos) até a versão 2.2.3 da biblioteca cliente mariadb. A partir da versão 2.2.4, ele começou a definir valores idênticos em todas as linhas para colunas que estávamos definindo
replace(uuid(),'-', '')
usando uma única instrução de atualização. Isso também acontece com várias outras versões do cliente mariadb, incluindo a mais recente (2.7.0).O problema está relacionado à função REPLACE() ou ao aninhamento de chamadas de função na atualização. Definitivamente não é causado pela função UUID().
O problema ocorre igualmente no MySQL 5.7.22 (instalado localmente no meu ambiente), MySQL 5.7.30 (contêiner do docker de teste) e, mais importante, Aurora DB (MySQL 5.6.10).
-------------------------------------------------- -- EDITAR ----------------------------------------------- -----
Para mim, isso foi causado por uma conjunção de:
Adicionando CONVERT() à imagem resolveu:
UPDATE sometable SET uuid=UNHEX(REPLACE(CONVERT(UUID() using utf8mb4), '-', '')) WHERE uuid IS NULL;
Para mais detalhes (e um upvote): https://stackoverflow.com/a/51393124/5154619
Eu tentei isso na versão 9 do MySQL/MariaDB:
Cada versão tem 4 linhas diferentes, portanto, 4 uuids diferentes.
Se você tem um código que produz o mesmo uuid, o que você está fazendo de diferente?
O problema com a implementação e definição de
uuid()
no mysql é que ele não é gerado de forma verdadeiramente aleatória, de modo que podem ocorrer colisões especialmente ao fazê-lo em massa.Melhor é usar o uuid v4, que garante aleatoriedade por toda parte veja uma implementação https://stackoverflow.com/a/32965744/5193536 é um pouco mais lento.