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 / 37034
Accepted
jd.
jd.
Asked: 2013-03-20 08:44:46 +0800 CST2013-03-20 08:44:46 +0800 CST 2013-03-20 08:44:46 +0800 CST

DELETE muito lento no PostgreSQL, solução alternativa?

  • 772

Eu tenho um banco de dados no PostgreSQL 9.2 que tem um esquema principal com cerca de 70 tabelas e um número variável de esquemas por cliente estruturados de forma idêntica de 30 tabelas cada. Os esquemas do cliente têm chaves estrangeiras que fazem referência ao esquema principal e não o contrário.

Acabei de começar a preencher o banco de dados com alguns dados reais retirados da versão anterior. O banco de dados atingiu cerca de 1,5 GB (espera-se que cresça para vários 10s GB em semanas) quando tive que fazer uma exclusão em massa em uma tabela muito central no esquema principal. Todas as chaves estrangeiras em questão são marcadas como ON DELETE CASCADE.

Não foi surpresa que isso demorasse muito, mas depois de 12 horas ficou claro que era melhor começar de novo, largar o banco de dados e iniciar a migração novamente. Mas e se eu precisar repetir essa operação mais tarde quando o banco de dados estiver ativo e muito maior? Existem métodos alternativos e mais rápidos?

Seria muito mais rápido se eu escrevesse um script que navegasse pelas tabelas dependentes, começando na tabela mais distante da tabela central, excluindo as linhas dependentes tabela por tabela?

Um detalhe importante é que existem triggers em algumas das tabelas.

postgresql performance
  • 6 6 respostas
  • 107361 Views

6 respostas

  • Voted
  1. Best Answer
    ailnlv
    2016-05-12T12:53:29+08:002016-05-12T12:53:29+08:00

    Eu tive um problema parecido. Acontece que esses ON DELETE CASCADEgatilhos estavam desacelerando um pouco as coisas, porque essas exclusões em cascata eram terrivelmente lentas.

    Resolvi o problema criando índices nos campos de chave estrangeira nas tabelas de referência e passei de algumas horas para a exclusão para alguns segundos.

    • 91
  2. Chris Travers
    2013-03-21T02:01:59+08:002013-03-21T02:01:59+08:00

    Você tem poucas opções. A melhor opção é executar uma exclusão em lote para que os gatilhos não sejam atingidos. Desative os gatilhos antes de excluir e, em seguida, reative-os. Isso economiza uma quantidade muito grande de tempo. Por exemplo:

    ALTER TABLE tablename DISABLE TRIGGER ALL; 
    DELETE ...; 
    ALTER TABLE tablename ENABLE TRIGGER ALL;
    

    Uma chave importante aqui é que você deseja minimizar a profundidade das subconsultas. Nesse caso, convém configurar tabelas temporárias para armazenar informações relevantes para evitar subconsultas profundas em sua exclusão.

    • 46
  3. Mikko Rantalainen
    2019-01-08T00:52:15+08:002019-01-08T00:52:15+08:00

    O método mais fácil de resolver o problema é consultar o tempo detalhado do PostgreSQL: EXPLAIN. Para isso, você precisa encontrar, no mínimo, uma única consulta que seja concluída, mas que demore mais do que o esperado. Digamos que a consulta lenta se pareça com

    delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';
    

    Em vez de realmente executar essa consulta, você pode fazer

    begin;
    explain (analyze,buffers,timing)
    delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';
    rollback;
    

    O rollbackno final permite executar isso sem realmente modificar o banco de dados. Você ainda obtém o tempo detalhado do que levou quanto. Depois de executar isso, você pode encontrar na saída que algum gatilho causa grandes atrasos:

    ...
    Trigger for constraint XYZ123: time=12311.292 calls=1
    ...
    

    O timeestá em ms (milissegundos), portanto, verificar essa restrição levou cerca de 12,3 segundos. Você precisa adicionar um novo INDEXsobre as colunas necessárias para que esse gatilho possa ser calculado de forma eficaz. Para referências de chave estrangeira, a coluna que faz referência a outra tabela deve ser indexada (ou seja, a coluna de origem, não a coluna de destino). O PostgreSQL não cria automaticamente esses índices para você e DELETEé a única consulta comum em que você realmente precisa desse índice. Como resultado, você pode ter acumulado anos de dados até atingir o caso em que DELETEestá muito lento devido à falta de um índice.

    A razão pela qual a coluna de origem precisa do índice é que quando você tem tabelas Xe Y, com Y.rreferência de chave estrangeira a X.id, a exclusão de qualquer linha da tabela Xrequer a verificação se existe uma linha Y.rapontando para essa linha na tabela . XSem um índice sobre o Y.rPostgreSQL, será necessário varrer toda a tabela Ypara verificar isso. Com o índice a verificação será rápida porque o índice pode dizer diretamente se tal valor existe em Y.r.

    Depois de corrigir o desempenho dessa restrição (ou alguma outra coisa que levou muito tempo), repita a consulta em begin/ rollbackbloco para poder comparar o novo tempo de execução com o tempo de execução anterior. Continue até ficar satisfeito com o tempo de resposta de exclusão de uma única linha (consegui que uma consulta fosse de 25,6 segundos para 15 ms ou cerca de 1700x mais rápido simplesmente adicionando índices diferentes). Então você pode prosseguir para concluir sua exclusão completa sem nenhum hack.

    Observe que, se você adicionar um novo índice e isso não melhorar o desempenho, pode ser uma boa ideia remover esse índice. Manter quaisquer índices atualizados quando novas linhas são adicionadas e removidas causará alguma perda de desempenho, portanto, você não deve ter índices sem uma necessidade real.

    (Observe que EXPLAINprecisa de uma consulta que possa ser concluída com êxito. Certa vez, tive um problema em que o PostgreSQL demorou muito para descobrir que uma exclusão violaria uma restrição de chave estrangeira e, nesse caso EXPLAIN, não pode ser usada porque não emitirá tempo para falhas consultas. Não conheço nenhuma maneira fácil de depurar problemas de desempenho nesse caso.)

    • 36
  4. Johann8
    2017-09-08T01:57:49+08:002017-09-08T01:57:49+08:00

    Desabilitar gatilhos pode ser uma ameaça à integridade do banco de dados e não pode ser recomendado; no entanto, se você tiver certeza de que sua operação é à prova de falhas, poderá desabilitar os gatilhos com o seguinte:

    SET session_replication_role = replica;
    

    Corre DELETEaqui.

    Para restaurar acionadores, execute:

    SET session_replication_role = DEFAULT;
    

    Fonte aqui.

    • 14
  5. blindguy
    2019-12-02T17:57:29+08:002019-12-02T17:57:29+08:00

    Se você tiver gatilhos ON DELETE CASCADE, esperamos que eles estejam lá por um motivo e, portanto, não devem ser desativados. Outro truque (ainda adicione seus índices) que funciona para mim é criar uma função de exclusão que exclui manualmente os dados começando com as tabelas no final da cascata e funciona em direção à tabela principal. (Isso é o mesmo que você teria que fazer se tivesse um gatilho ON DELETE RESTRICT)

    CREATE TABLE tablea (
        tablea_uid integer
    );
    
    CREATE TABLE tableb (
        tableb_uid integer,
        tablea_rid integer REFERENCES tablea(tablea_uid)
    );
    
    CREATE TABLE tablec (
        tablec_uid integer,
        tableb_rid integer REFERENCES tableb(tableb_uid)
    );
    

    Nesse caso, exclua os dados em tablec, em seguida, em tableb, em seguida, em tablea

    CREATE OR REPLACE FUNCTION delete_in_order()
     RETURNS void AS $$
    
        DELETE FROM tablec;
        DELETE FROM tableb;
        DELETE FROM tablea;
    
    $$ LANGUAGE SQL;
    
    • 2
  6. marcel
    2021-01-01T10:35:28+08:002021-01-01T10:35:28+08:00

    Para mim, o truque foi descartar a restrição fk de outra tabela de referência . Esta tabela de referência era enorme. Mas cuidado, eu sabia que aquela restrição para os registros que eu tinha que deletar não era relevante. Portanto, eu poderia descartar temporariamente a restrição para adicioná-la posteriormente (durante a qual eu tinha certeza de que não havia outra atividade de banco de dados).

    • 2

relate perguntas

  • Sequências Biológicas do UniProt no PostgreSQL

  • Como determinar se um Índice é necessário ou necessário

  • Onde posso encontrar o log lento do mysql?

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

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • 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

    Conceder acesso a todas as tabelas para um usuário

    • 5 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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