Gerencio um aplicativo que possui 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 SProcs, sem gatilhos ou qualquer coisa), é apenas um armazenamento de dados.
Todo mês, somos obrigados a limpar os registros das duas tabelas principais. O critério para a limpeza varia e é 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-5 milhões de linhas por semana através de importações).
Atualmente, temos que fazer essa exclusão em lotes de cerca de 50.000 linhas (ou seja, excluir 50000, confirmar, excluir 50000, confirmar, repetir). Tentar excluir o lote inteiro de uma só vez deixa o banco de dados sem resposta por cerca de uma hora (dependendo do número de linhas). A exclusão das linhas em lotes como esse é muito difícil para o sistema e normalmente precisamos fazê-lo "conforme o tempo permitir" ao longo de uma semana; permitir que o script seja executado continuamente pode resultar em uma degradação do desempenho que é inaceitável para o usuário.
Acredito que esse tipo de exclusão de lote também prejudica o desempenho do índice e tem outros impactos que acabam causando 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 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;
Esse banco de dados deve estar acima de 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?
fonte
Respostas:
A lógica com 'A' e 'B' pode estar "oculta" atrás de uma coluna virtual na qual você pode fazer o particionamento:
fonte
A solução clássica para isso é particionar suas tabelas, por exemplo, por mês ou por semana. Se você nunca as encontrou antes, uma tabela particionada é como várias tabelas estruturadas de forma idêntica, implícitas
UNION
na seleção, 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áloga a umaTRUNCATE
em termos de carga, porque é isso que você realmente está fazendo - truncando ou descartando uma dessas sub-tabelas invisíveis). Será uma quantidade significativa de processamento para particionar "após o fato", mas não faz sentido chorar por 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 facilmente isso com aDBMS_JOB
).E com as partições, você também pode explorar a consulta paralela e a eliminação da partição , o que deve deixar seus usuários muito felizes ...
fonte
A
, então, seDateA
é mais de 3 anos, ele é purgado. Se o Status forB
eDateB
tiver mais de 10 anos, ele será removido. Se minha compreensão do particionamento estiver correta, o particionamento não seria útil em uma situação como essa (pelo menos no que diz respeito à remoção).Um aspecto a considerar é quanto do desempenho da exclusão resulta dos índices e quanto da tabela bruta. Todo registro excluído da tabela requer a mesma exclusão da linha de todo índice btree. Se você possui mais de 30 índices btree, suspeito que a maior parte do seu tempo seja gasta em manutenção de índices.
Isso afeta a 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 ao 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, portanto, você pode precisar fazer apenas dois saltos, mas ainda assim poderá fazer 100 leituras, em vez das 5 anteriores.
Se eles são í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 IOs para retornar um único registro, estava usando 10.000 IOs. Como tal, a sobrecarga extra em partições extras para o índice não importa.
fonte
a exclusão de 50 milhões de registros por mês em lotes de 50.000 é de apenas 1000 iterações. se você excluir 1 a cada 30 minutos, ele deverá atender aos seus requisitos. uma tarefa agendada para executar a consulta que você postou, mas remover o loop para que seja executada apenas uma vez, não deve causar uma degradação perceptível para os usuários. Fazemos 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, distribuímos um pouco mais de 10.000 registros a cada 10 minutos, que são executados em cerca de 1 ou 2 segundos em execução nos servidores Oracle unix.
fonte
Se o espaço em disco não for muito importante, 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 a exclusão dos registros. Você pode fazer a instrução create em paralelo e com a dica anexa para torná-la rápida e criar todos os seus índices. Em seguida, quando terminar, (e testado), renomeie a tabela existente paramy_table_old
e renomeie a tabela "trabalho" paramy_table
. Quando estiver confortável com tudodrop my_table_old purge
para se livrar da mesa antiga. Se houver várias restrições de chave estrangeira, consulte odbms_redefinition
pacote PL / SQL . Clonará seus índices, restrições, etc. ao usar as opções apropriadas. Este é um resumo de uma sugestão de Tom Kyte, da AskTomfama. Após a primeira execução, você pode automatizar tudo, e a tabela de criação deve ser muito mais rápida, e isso pode ser feito enquanto o sistema estiver ativo, e o tempo de inatividade do aplicativo seria limitado a menos de um minuto para renomear as tabelas. O uso do CTAS será muito mais rápido do que fazer várias exclusões de lotes. Essa abordagem pode ser particularmente útil se você não tiver o particionamento licenciado.Amostra de CTAS, mantendo linhas com dados dos últimos 365 dias e
flag_inactive = 'N'
:fonte
ao descartar uma partição, você deixa os índices globais inutilizáveis, que precisam ser reconstruídos; a reconstrução dos índices globais seria um grande problema; como se você fizer isso on-line, 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 o uso de exclusão em lote PL / SQL, várias horas está ok, eu acho.
fonte