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 / 249718
Accepted
Joe
Joe
Asked: 2019-09-27 11:15:11 +0800 CST2019-09-27 11:15:11 +0800 CST 2019-09-27 11:15:11 +0800 CST

Como inserir valores em um banco de dados altamente normalizado sem verificação excessiva de duplicatas?

  • 772

A situação:

O líder do nosso projeto decidiu usar um banco de dados altamente normalizado como nosso design de banco de dados. O que significa que literalmente todos os campos de uma tabela grande são um ID em vez do valor real. Sua intenção é não ter duplicatas de qualquer tipo, mesmo em lugares onde duplicatas não machucam (primeiros nomes de pessoas, esse tipo de coisa).

No entanto, isso leva a um problema: ao inserir novos dados, precisamos verificar cada subtabela para ver se o valor existe (primeira consulta) e inseri-lo se não existir (segunda consulta) ou então recuperar o ID, fazer isso para literalmente todas as colunas da tabela principal (então 30 vezes ou algo assim), e então podemos criar o objeto que realmente queríamos obter. (São ~60 acessos ao banco de dados para criar um objeto!).

Trabalhamos na primavera, então usamos jdbcTemplate para construir uma conexão de banco de dados, e cada consulta é cara. Quando estamos inserindo milhares de novos registros ou atualizando-os, isso na verdade torna o banco de dados muito lento.

Todo esse processo parece completamente sujo e errado para mim e, portanto, queria perguntar: existe uma maneira melhor? É possível fazer uma subconsulta inserir um valor se não existir, ou não, se existir, e retornar a chave real em ambos os casos, que é usada imediatamente para definir o ID na tabela principal? Existe uma solução elegante para reduzir o número de consultas sem introduzir muito SQL complicado (para o bem dos membros da equipe)?

mysql mariadb
  • 2 2 respostas
  • 2458 Views

2 respostas

  • Voted
  1. Best Answer
    Akina
    2019-09-27T23:06:17+08:002019-09-27T23:06:17+08:00

    Um pequeno pensamento...

    Formalmente você tem algo parecido com esta estrutura simplificada:

    CREATE TABLE slave1 (id PK, value UNIQUE);
    CREATE TABLE slave2 (id PK, value UNIQUE);
    CREATE TABLE main (id PK, id_slave1 FK, id_slave2 FK);
    

    Quando você precisa inserir 2 registros (id_1, val_1_1, val_1_2) e (id_2, val_2_1, val_2_2), você executa:

    CREATE TEMPORARY TABLE temp (val_slave1, val_slave2) [ENGINE=Memory];
    
    INSERT INTO temp (val_slave1, val_slave2)
    VALUES (val_1_1, val_1_2),
           (val_2_1, val_2_2);
    
    INSERT IGNORE INTO slave1 (value)
    SELECT DISTINCT val_slave1
    FROM temp;
    
    INSERT IGNORE INTO slave2 (value)
    SELECT DISTINCT val_slave2
    FROM temp;
    
    INSERT INTO main (id_slave1, id_slave2)
    SELECT slave1.id, slave2.id
    FROM temp
    JOIN slave1 ON temp.val_slave1 = slave1.value
    JOIN slave2 ON temp.val_slave2 = slave2.value;
    

    O mecanismo de temppode ser Memory quando a quantidade de valores inseridos for baixa, e InnoDB ou qualquer outra coisa se o array de dados inserido for enorme.

    INSERT IGNORE funciona rápido o suficiente no campo indexado UNIQUE. Garante que não haja duplicatas nas tabelas escravas, e que os valores que devem ser inseridos existirão nas escravas durante a inserção na tabela principal.

    E a consulta final também deve ser rápida - especialmente quando os campos de tabela temporários também são indexados.

    Se você precisar inserir apenas um registro, então você pode, claro, não usar tabela temp... mas acho que a uniformidade é mais segura do que uma pequena simplificação.

    Claro, isso pode ser otimizado. Por exemplo, todas as inserções podem ser unidas em um procedimento armazenado, e você não precisa em "60 acessos ao banco de dados", uma CHAMADA é suficiente. Finalmente você deve executar apenas 3 consultas independentes pela contagem de registros para inserir. E apenas um deles (inserindo em temptable) pode ser enorme (ou mesmo pode ser dividido em vários inserts).

    • 3
  2. Rick James
    2019-10-07T12:00:40+08:002019-10-07T12:00:40+08:00

    Se você puder agrupar os dados, posso fornecer uma técnica que envolve 2 consultas por lote - uma para inserir novos nomes para o lote, outra para encontrar todos os ids. E não desperdiça ids, como REPLACE, INSERT IGNORE, IODKU, etc.

    1. Crie uma tabela temporária com todos os dados desnormalizados. Tem colunas vagas para os ids.
    2. Execute as 2 consultas para cada coluna que precisa ser normalizada. (2*30 consultas no seu caso).
    3. INSERT .. SELECT ..para mover os dados para a(s) tabela(s) real(is).
    4. Trunque ou elimine a tabela temporária.

    Ver Normalização em Massa

    Isso foi projetado (e aperfeiçoado anos atrás) quando eu precisava colocar grandes quantidades de dados (possivelmente provenientes de muitos clientes) em tabelas e alguma normalização (não total) era necessária.

    No começo eu tinha INSERT IGNORE, mas rapidamente percebi que era provável que eu ficasse sem ids de auto_increment. Eu não estava disposto a usar 8 bytes BIGINTs. Afinal, um dos propósitos de normalizá-lo é economizar espaço.

    • 0

relate perguntas

  • 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