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 / 710
Accepted
Coding Gorilla
Coding Gorilla
Asked: 2011-01-20 09:30:55 +0800 CST2011-01-20 09:30:55 +0800 CST 2011-01-20 09:30:55 +0800 CST

Melhor maneira de excluir um conjunto de registros muito grande no Oracle

  • 772

Eu gerencio um aplicativo que tem um back-end de banco de dados Oracle muito grande (quase 1 TB de dados com mais de 500 milhões de linhas em uma tabela). O banco de dados realmente não faz nada (sem SPocs, sem gatilhos ou qualquer coisa), é apenas um armazenamento de dados.

Todos os meses, somos obrigados a limpar os registros das duas tabelas principais. Os critérios para a eliminação variam e são uma combinação de idade da linha e alguns campos de status. Normalmente, acabamos limpando entre 10 e 50 milhões de linhas por mês (adicionamos cerca de 3 a 5 milhões de linhas por semana por meio de importações).

Atualmente, temos que fazer essa exclusão em lotes de cerca de 50.000 linhas (ou seja, excluir 50.000, confirmar, excluir 50.000, confirmar, repetir). A tentativa de excluir todo o lote de uma só vez faz com que o banco de dados não responda por cerca de uma hora (dependendo do número de linhas). Excluir as linhas em lotes como este é muito difícil para o sistema e normalmente temos que fazer isso "conforme o tempo permitir" ao longo de uma semana; permitir que o script seja executado continuamente pode resultar em uma degradação de desempenho que é inaceitável para o usuário.

Acredito que esse tipo de exclusão em lote também degrada o desempenho do índice e tem outros impactos que eventualmente causam a degradação do desempenho do banco de dados. Existem 34 índices em apenas uma tabela, e o tamanho dos dados do índice é realmente maior do que os próprios dados.

Aqui está o script que um de nossos funcionários de TI usa para fazer essa limpeza:

BEGIN
LOOP

delete FROM tbl_raw 
  where dist_event_date < to_date('[date]','mm/dd/yyyy') and rownum < 50000;

  exit when SQL%rowcount < 49999;

  commit;

END LOOP;

commit;

END;

Este banco de dados deve estar em 99,99999% e só temos uma janela de manutenção de 2 dias uma vez por ano.

Estou procurando um método melhor para remover esses registros, mas ainda não encontrei nenhum. Alguma sugestão?

oracle oracle-11g
  • 6 6 respostas
  • 80788 Views

6 respostas

  • Voted
  1. Best Answer
    René Nyffenegger
    2011-01-20T13:45:44+08:002011-01-20T13:45:44+08:00

    A lógica com 'A' e 'B' pode estar "escondida" atrás de uma coluna virtual na qual você pode fazer o particionamento:

    alter session set nls_date_format = 'yyyy-mm-dd';
    drop   table tq84_partitioned_table;
    
    create table tq84_partitioned_table (
      status varchar2(1)          not null check (status in ('A', 'B')),
      date_a          date        not null,
      date_b          date        not null,
      date_too_old    date as
                           (  case status
                                     when 'A' then add_months(date_a, -7*12)
                                     when 'B' then            date_b
                                     end
                            ) virtual,
      data            varchar2(100) 
    )
    partition   by range  (date_too_old) 
    ( 
      partition p_before_2000_10 values less than (date '2000-10-01'),
      partition p_before_2000_11 values less than (date '2000-11-01'),
      partition p_before_2000_12 values less than (date '2000-12-01'),
      --
      partition p_before_2001_01 values less than (date '2001-01-01'),
      partition p_before_2001_02 values less than (date '2001-02-01'),
      partition p_before_2001_03 values less than (date '2001-03-01'),
      partition p_before_2001_04 values less than (date '2001-04-01'),
      partition p_before_2001_05 values less than (date '2001-05-01'),
      partition p_before_2001_06 values less than (date '2001-06-01'),
      -- and so on and so forth..
      partition p_ values less than (maxvalue)
    );
    
    insert into tq84_partitioned_table (status, date_a, date_b, data) values 
    ('B', date '2008-04-14', date '2000-05-17', 
     'B and 2000-05-17 is older than 10 yrs, must be deleted');
    
    
    insert into tq84_partitioned_table (status, date_a, date_b, data) values 
    ('B', date '1999-09-19', date '2004-02-12', 
     'B and 2004-02-12 is younger than 10 yrs, must be kept');
    
    
    insert into tq84_partitioned_table (status, date_a, date_b, data) values 
    ('A', date '2000-06-16', date '2010-01-01', 
     'A and 2000-06-16 is older than 3 yrs, must be deleted');
    
    
    insert into tq84_partitioned_table (status, date_a, date_b, data) values 
    ('A', date '2009-06-09', date '1999-08-28', 
     'A and 2009-06-09 is younger than 3 yrs, must be kept');
    
    select * from tq84_partitioned_table order by date_too_old;
    
    -- drop partitions older than 10 or 3 years, respectively:
    
    alter table tq84_partitioned_table drop partition p_before_2000_10;
    alter table tq84_partitioned_table drop partition p_before_2000_11;
    alter table tq84_partitioned_table drop partition p2000_12;
    
    select * from tq84_partitioned_table order by date_too_old;
    
    • 18
  2. Gaius
    2011-01-20T10:16:33+08:002011-01-20T10:16:33+08:00

    A solução clássica para isso é particionar suas tabelas, por exemplo, por mês ou por semana. Se você não os encontrou antes, uma tabela particionada é como várias tabelas estruturadas de forma idêntica com um implícito UNIONao selecionar, e o Oracle armazenará automaticamente uma linha na partição apropriada ao inseri-la com base nos critérios de particionamento. Você menciona índices - bem, cada partição também recebe seus próprios índices particionados. É uma operação muito barata no Oracle descartar uma partição (é análogo a umTRUNCATEem termos de carga porque é isso que você está realmente fazendo - truncando ou descartando uma dessas subtabelas invisíveis). Será uma quantidade significativa de processamento para particionar "após o fato", mas não faz sentido chorar sobre o leite derramado - as vantagens de fazer até agora superam os custos. Todo mês você dividiria a partição superior para criar uma nova partição para os dados do próximo mês (você pode automatizar isso facilmente com um DBMS_JOB).

    E com partições você também pode explorar consultas paralelas e eliminação de partições , o que deve deixar seus usuários muito felizes...

    • 14
  3. Gary
    2011-01-20T14:17:42+08:002011-01-20T14:17:42+08:00

    Um aspecto a ser considerado é quanto do desempenho de exclusão resulta dos índices e quanto da tabela bruta. Cada registro excluído da tabela requer a mesma exclusão da linha de cada índice btree. Se você tiver mais de 30 índices btree, suspeito que a maior parte do seu tempo seja gasto na manutenção do índice.

    Isso tem um impacto na utilidade do particionamento. Digamos que você tenha um índice no nome. Um índice Btree padrão, tudo em um segmento, pode ter que fazer quatro saltos para ir do bloco raiz para o bloco folha e uma quinta leitura para obter a linha. Se esse índice for particionado em 50 segmentos e você não tiver a chave de partição como parte da consulta, cada um desses 50 segmentos precisará ser verificado. Cada segmento será menor, então você pode ter que fazer apenas 2 saltos, mas ainda pode acabar fazendo 100 leituras em vez das 5 anteriores.

    Se forem índices de bitmap, as equações são diferentes. Você provavelmente não está usando índices para identificar linhas individuais, mas sim conjuntos delas. Portanto, em vez de uma consulta usando 5 E/S para retornar um único registro, ela estava usando 10.000 E/S. Como tal, a sobrecarga extra em partições extras para o índice não importa.

    • 4
  4. Jason Jakob
    2013-10-02T11:22:16+08:002013-10-02T11:22:16+08:00

    a exclusão de 50 milhões de registros por mês em lotes de 50.000 é de apenas 1.000 iterações. se você fizer 1 exclusão a cada 30 minutos, deve atender às suas necessidades. uma tarefa agendada para executar a consulta que você postou, mas remova o loop para que ele seja executado apenas uma vez, não deve causar uma degradação perceptível aos usuários. Fazemos praticamente o mesmo volume de registros em nossa fábrica que funciona praticamente 24 horas por dia, 7 dias por semana e atende às nossas necessidades. Na verdade, espalhamos um pouco mais de 10.000 registros a cada 10 minutos, que são executados em cerca de 1 ou 2 segundos em nossos servidores Oracle unix.

    • 2
  5. Mark Stewart
    2014-12-18T05:16:08+08:002014-12-18T05:16:08+08:00

    Se o espaço em disco não for um prêmio, você poderá criar uma cópia "de trabalho" da tabela, digamos my_table_new, usando CTAS (Criar tabela como seleção) com critérios que omitiriam os registros a serem descartados. Você pode fazer a instrução create em paralelo e com a dica de acréscimo para torná-la rápida e, em seguida, criar todos os seus índices. Então, uma vez terminado (e testado), renomeie a tabela existente para my_table_olde renomeie a tabela "trabalho" para my_table. Uma vez que você está confortável com tudo drop my_table_old purgepara se livrar da mesa velha. Se houver um monte de restrições de chave estrangeira, dê uma olhada no dbms_redefinition pacote PL/SQL . Ele clonará seus índices, restrições, etc. ao usar as opções apropriadas. Este é um resumo de uma sugestão de Tom Kyte do AskTomfama. Após a primeira execução, você pode automatizar tudo, e a criação da tabela deve ser muito mais rápida, podendo ser feita enquanto o sistema estiver ativo, e o tempo de inatividade do aplicativo seria limitado a menos de um minuto para fazer a renomeação das tabelas. Usar CTAS será muito mais rápido do que fazer várias exclusões em lote. Essa abordagem pode ser particularmente útil se você não tiver o particionamento licenciado.

    CTAS de amostra, mantendo linhas com dados dos últimos 365 dias e flag_inactive = 'N':

    create /*+ append */ table my_table_new 
       tablespace data as
       select /*+ parallel */ * from my_table 
           where some_date >= sysdate -365 
           and flag_inactive = 'N';
    
    -- test out my_table_new. then if all is well:
    
    alter table my_table rename to my_table_old;
    alter table my_table_new rename to my_table;
    -- test some more
    drop table my_table_old purge;
    
    • 1
  6. iceburge5
    2012-06-29T17:18:09+08:002012-06-29T17:18:09+08:00

    ao descartar uma partição, você deixa índices globais inutilizáveis, que precisam reconstruir, a reconstrução de índices globais seria um grande problema, pois se você fizer isso online, será bastante lento, caso contrário, você precisará de tempo de inatividade. em ambos os casos, não pode atender ao requisito.

    "Normalmente acabamos limpando entre 10 e 50 milhões de linhas por mês"

    eu recomendaria usar a exclusão de lote PL/SQL, várias horas está ok, eu acho.

    • 0

relate perguntas

  • Backups de banco de dados no Oracle - Exportar o banco de dados ou usar outras ferramentas?

  • ORDER BY usando prioridades personalizadas para colunas de texto

  • Interface sqlplus confortável? [fechado]

  • Como encontrar as instruções SQL mais recentes no banco de dados?

  • Como posso consultar nomes usando expressões regulares?

Sidebar

Stats

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

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

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

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

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 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
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +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
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +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