Introdução
Ei. Eu sou ningenMe, um desenvolvedor web.
Como o título diz, minha história é sobre a exclusão física de 300 milhões de registros no MySQL.
Fiquei interessado nisso, então decidi fazer um memorando (instrução).
Iniciar - Alerta
O servidor de lote que uso e mantenho tem um processo regular que coleta dados do último mês do MySQL uma vez por dia.
Normalmente, este processo é concluído em cerca de 1 hora, mas desta vez não foi concluído em 7 ou 8 horas e o alerta não parou de rastejar para fora ...
Procurando por um motivo
Tentei reiniciar o processo, olhei os logs, mas não vi nada terrível.
A solicitação foi indexada corretamente. Mas quando me perguntei o que estava errado, percebi que o tamanho do banco de dados é muito grande.
hoge_table | 350'000'000 |
350 milhões de registros. A indexação parece estar funcionando corretamente, apenas muito lenta.
A coleta de dados necessária por mês foi de cerca de 12 milhões de registros. Parece que o comando select demorou muito e a transação não foi executada por um longo tempo.
DB
Basicamente, é uma tabela que cresce cerca de 400.000 registros todos os dias. O banco de dados deveria coletar dados apenas do último mês, portanto, o cálculo estava no fato de que suportará exatamente essa quantidade de dados, mas, infelizmente, a operação de rotação não foi incluída.
Este banco de dados não foi desenvolvido por mim. Eu adquiri de outro desenvolvedor, então parecia que era uma dívida técnica.
Chegou o momento em que a quantidade de dados inseridos diariamente se tornou grande e finalmente atingiu seu limite. Supõe-se que trabalhando com uma quantidade tão grande de dados seria necessário separá-los, mas isso, infelizmente, não foi feito.
E então eu entrei.
Correção
Era mais racional reduzir o próprio banco de dados e reduzir o tempo de seu processamento do que alterar a própria lógica.
A situação deveria mudar significativamente se 300 milhões de registros fossem apagados, então decidi fazer isso ... Eh, achei que definitivamente funcionaria.
Passo 1
Tendo preparado um backup confiável, finalmente comecei a enviar solicitações.
「Enviando uma solicitação」
DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';
「...」
「...」
“Hmm… Sem resposta. Talvez o processo esteja demorando muito? " - pensei, mas para o caso de olhei na grafana e vi que a carga do disco estava crescendo muito rápido.
"Perigoso" - pensei novamente e imediatamente interrompi o pedido.
Passo 2
Depois de analisar tudo, percebi que a quantidade de dados era muito grande para excluir tudo de uma vez.
Decidi escrever um script que pudesse excluir cerca de 1.000.000 de registros e o executei.
「Eu implementei o script」
"Agora com certeza vai funcionar", pensei
etapa 3
O segundo método funcionou, mas consumiu muito tempo.
Para fazer tudo com perfeição, sem nervos extras, levaria cerca de duas semanas. Mesmo assim, esse cenário não atendia aos requisitos de serviço, então tive que sair dele.
Portanto, aqui está o que decidi fazer:
Copie a tabela e renomeie
Na etapa anterior, percebi que excluir uma quantidade tão grande de dados cria uma carga igualmente grande. Portanto, decidi criar uma nova tabela do zero usando insert e mover os dados que eu iria excluir para ela.
| hoge_table | 350'000'000|
| tmp_hoge_table | 50'000'000|
Se você fizer a nova tabela com o mesmo tamanho que acima, a velocidade de processamento também deve se tornar 1/7 mais rápida.
Depois de criar a tabela e renomeá-la, comecei a usá-la como tabela mestre. Agora, se eu eliminar uma tabela com 300 milhões de registros, tudo ficará bem.
Descobri que truncar ou descartar é menos sobrecarga do que excluir e decidi usar esse método.
atuação
「Enviando uma solicitação」
INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';
「...」
「...」
「uh ...?」
Passo 4
Achei que a ideia anterior funcionaria, mas após enviar a solicitação de inserção, vários erros apareceram. O MySQL não é econômico.
Já estava tão cansado que comecei a pensar que não queria mais fazer isso.
Sentei e pensei e percebi que talvez houvesse muitas solicitações de inserção para uma vez ...
Tentei enviar uma solicitação de inserção para a quantidade de dados que o banco de dados deve processar em 1 dia. Aconteceu!
Bem, depois disso, continuamos a enviar solicitações com a mesma quantidade de dados. Como precisamos remover a quantidade mensal de dados, repetimos essa operação cerca de 35 vezes.
Renomeando uma mesa
Aqui, a sorte estava do meu lado: tudo correu bem.
Alerta apagado
A velocidade de processamento em lote aumentou.
Anteriormente, esse processo demorava cerca de uma hora, agora leva cerca de 2 minutos.
Depois de me convencer de que todos os problemas foram resolvidos, perdi 300 milhões de registros. Excluí a planilha e me senti renascido.
Resumindo
Percebi que o processamento rotativo era negligenciado no processamento em lote e esse era o principal problema. Este erro arquitetônico é uma perda de tempo.
Você pensa sobre a carga de replicação de dados excluindo registros do banco de dados? Não vamos sobrecarregar o MySQL.
Aqueles que são bem versados em bancos de dados definitivamente não enfrentarão esse problema. De resto, espero que este artigo tenha sido útil.
Obrigado por ler!
Ficaremos muito felizes se você nos contar se gostou deste artigo, a tradução foi clara, foi útil para você?