AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 269189
Accepted
Déjà vu
Déjà vu
Asked: 2020-06-16 05:41:37 +0800 CST2020-06-16 05:41:37 +0800 CST 2020-06-16 05:41:37 +0800 CST

Comportamento do MySQL UUID()

  • 772

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 tdeuu varchar(36)
  • inserindo 10.000.000 de linhas uucomnull
  • fiz oUPDATE t SET uu=UUID();

e todas as linhas de 10 milhões têm um UUID diferente e exclusivo .

mysql innodb
  • 3 3 respostas
  • 2960 Views

3 respostas

  • Voted
  1. Davi Cavalcanti
    2020-10-23T19:44:37+08:002020-10-23T19:44:37+08:00

    Estou tendo exatamente esse mesmo problema agora.

    Eu escrevi um exemplo de aplicativo java para demonstrar o problema:

    MariaDBTestUUID.java:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class MariaDBTestUUID
    {
        private Connection connect;
        private Statement statement;
        private ResultSet resultSet;
    
        public void updateUUID() throws Exception
        {
            try
            {
                // This will load the MySQL driver, each DB has its own driver
                Class.forName("org.mariadb.jdbc.Driver");
                // Setup the connection with the DB
                connect = DriverManager
                        // AWS Aurora (MySQL server 5.6.10) - found with SQL "show variables like '%version%';"
                        .getConnection("jdbc:mariadb://<hostname>:3306/<DB name>?user=<user>&password=<password>");
    //                     // local MySQL server (5.7.22)
    //                    .getConnection("jdbc:mariadb://localhost:3306/licenceserver4?user=root&password=<password>");
    //                     // docker container MySQL server (5.7.30)
    //                    .getConnection("jdbc:mariadb://localhost:3307/testDB?user=root&password=<password>");
    
                // PreparedStatements can use variables and are more efficient
                PreparedStatement preparedStatement =
                    connect.prepareStatement("UPDATE testUUID SET new_id = uuid(), new_id2 = REPLACE(uuid(), '-', ''), new_id3 = UNHEX(REPLACE(uuid(), '-', ''))");
                preparedStatement.executeUpdate();
    
                queryStrings("select ID, new_ID, new_ID2, hex(new_ID3) as new_ID3 from testUUID");
                queryStrings("select count(distinct(new_ID)) as distinct_rows from testUUID");
                queryStrings("select count(distinct(new_ID2)) as distinct_rows2 from testUUID");
                queryStrings("select count(distinct(new_ID3)) as distinct_rows3 from testUUID");
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                close();
            }
        }
    
        private void queryStrings(String sql) throws SQLException
        {
            System.out.println("Running \"" + sql + "\"... ");
            statement = connect.createStatement();
            // Result set get the result of the SQL query
            resultSet = statement
                .executeQuery(sql);
            writeResultSet(resultSet);
        }
    
        private void writeResultSet(ResultSet resultSet) throws SQLException
        {
            // ResultSet is initially before the first data set
            while (resultSet.next())
            {
                // we can only do this because we know they are all strings
                for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++)
                {
                    String value = resultSet.getString(i);
                    System.out.print(resultSet.getMetaData().getColumnName(i) + ": " + value + ", ");
                }
                System.out.println();
            }
        }
    
        // You need to close the resultSet
        private void close()
        {
            try
            {
                if (resultSet != null)
                {
                    resultSet.close();
                }
    
                if (statement != null)
                {
                    statement.close();
                }
    
                if (connect != null)
                {
                    connect.close();
                }
            }
            catch (Exception e)
            {
                System.out.println("Error closing:");
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) throws Exception
        {
            new MariaDBTestUUID().updateUUID();
        }
    }
    

    A versão da biblioteca cliente é definida aqui:

    build.gradle:

    plugins {
        id 'java'
    }
    
    sourceCompatibility = 11
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        // DB driver
        runtimeOnly 'org.mariadb.jdbc:mariadb-java-client:2.2.4'
    }
    

    Para executar o aplicativo de teste, basta:

    1 - conecte-se a cada um dos BDs e execute as seguintes consultas:

    create table testUUID (ID int, new_ID varchar(100), new_ID2 varchar(100), new_ID3 BINARY(16));
    insert into testUUID (id) values (1),(2),(3);
    

    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:

    • Com o cliente mariadb 2.2.3, ele retorna 3 para todas as consultas.
    • Com o cliente mariadb 2.2.4, ele retorna 1 para a segunda e terceira consultas (new_ID2 e new_ID3).

    Então, minhas descobertas até agora:

    1. 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).

    2. 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().

    3. 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:

    • o conjunto de caracteres do banco de dados
    • uma mudança no MariaDB J/Connector a partir da versão 2.2.4
    • a combinação de funções de processamento UUID() e String (como REPLACE())

    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

    • 1
  2. Best Answer
    Rick James
    2020-06-17T17:21:46+08:002020-06-17T17:21:46+08:00

    Eu tentei isso na versão 9 do MySQL/MariaDB:

    CREATE TABLE t (
        i INT,
        myuuid CHAR(36) NULL
        ) ENGINE=InnoDB;
    
    INSERT INTO t (i) VALUES
        (1), (2), (3), (4);
    
    UPDATE t SET myuuid = UUID();
    
    SELECT DISTINCT myuuid FROM t;
    

    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?

    • 0
  3. nbk
    2020-06-16T05:52:37+08:002020-06-16T05:52:37+08:00

    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.

    • -1

relate perguntas

  • Existem ferramentas de benchmarking do MySQL? [fechado]

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Quando é o momento certo para usar o MariaDB em vez do MySQL e por quê?

  • Como um grupo pode rastrear alterações no esquema do banco de dados?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve