La historia de la eliminación física de 300 millones de registros en MySQL

introducción

Hola. Soy ningenMe, desarrollador web.

Como dice el título, mi historia es la historia de cómo eliminar físicamente 300 millones de registros en MySQL.

Me interesé en esto, así que decidí hacer un recordatorio (instrucciones).

Inicio - Alerta

El servidor por lotes que uso y mantengo tiene un proceso regular que recopila los datos del último mes de MySQL una vez al día.

Generalmente este proceso se completa en aproximadamente 1 hora, pero esta vez no se completó durante 7 u 8 horas y la alerta no dejó de aparecer...

Buscando una razón

Intenté reiniciar el proceso y mirar los registros, pero no vi nada malo.
La consulta se indexó correctamente. Pero cuando pensé en lo que estaba pasando, me di cuenta de que el tamaño de la base de datos es bastante grande.

hoge_table | 350'000'000 |

350 millones de registros. La indexación parecía funcionar correctamente, aunque muy lenta.

La recopilación de datos requerida por mes fue de aproximadamente 12 de registros. Parece que el comando de selección tomó mucho tiempo y la transacción no se ejecutó durante mucho tiempo.

DB

Es esencialmente una tabla que crece alrededor de 400 entradas cada día. Se suponía que la base de datos recopilaría datos solo del último mes, por lo que se esperaba que soportaría exactamente esta cantidad de datos, pero, desafortunadamente, la operación de rotación no se incluyó.

Esta base de datos no fue desarrollada por mí. Lo tomé de otro desarrollador, por lo que todavía lo sentía como una deuda técnica.

Llegó un momento en el que el volumen de datos insertados diariamente se hizo grande y finalmente llegó a su límite. Se supone que cuando se trabaja con una cantidad tan grande de datos, sería necesario separarlos, pero lamentablemente esto no se hizo.

Y entonces entré en acción.

Corrección

Era más racional reducir el tamaño de la base de datos y reducir el tiempo de procesamiento que cambiar la lógica misma.

La situación debería cambiar significativamente si borras 300 millones de registros, así que decidí hacerlo... Eh, pensé que esto definitivamente funcionaría.

Acción 1

Habiendo preparado una copia de seguridad confiable, finalmente comencé a enviar solicitudes.

「Enviando una solicitud」

DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';

"..."

"..."

“Hmm… No hay respuesta. ¿Quizás el proceso lleva mucho tiempo? — Pensé, pero por si acaso miré a Grafana y vi que la carga del disco estaba creciendo muy rápidamente.
“Peligroso”, pensé de nuevo e inmediatamente detuve la solicitud.

Acción 2

Después de analizar todo, me di cuenta de que el volumen de datos era demasiado grande para borrarlo todo de una vez.

Decidí escribir un script que pudiera eliminar alrededor de 1 de registros y lo ejecuté.

「Implemente el guión」

"Esto definitivamente funcionará", pensé.

Acción 3

El segundo método funcionó, pero resultó ser muy laborioso.
Hacer todo con cuidado, sin nervios innecesarios, llevaría unas dos semanas. Pero aún así, este escenario no cumplía con los requisitos del servicio, por lo que tuvimos que alejarnos de él.

Así que esto es lo que decidí hacer:

Copie la tabla y cámbiele el nombre.

En el paso anterior, me di cuenta de que eliminar una cantidad tan grande de datos crea una carga igualmente grande. Entonces decidí crear una nueva tabla desde cero usando Insertar y mover allí los datos que iba a eliminar.

| hoge_table     | 350'000'000|
| tmp_hoge_table |  50'000'000|

Si hace que la nueva tabla tenga el mismo tamaño que la anterior, la velocidad de procesamiento de datos también debería ser 1/7 más rápida.

Después de crear la tabla y cambiarle el nombre, comencé a usarla como tabla maestra. Ahora, si dejo caer la tabla con 300 millones de registros, todo debería estar bien.
Descubrí que truncar o eliminar genera menos gastos generales que eliminar y decidí usar este método.

Rendimiento

「Enviando una solicitud」

INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';

"..."
"..."
"¿Em...?"

Acción 4

Pensé que la idea anterior funcionaría, pero después de enviar la solicitud de inserción, aparecieron varios errores. MySQL no perdona.

Ya estaba tan cansada que comencé a pensar que ya no quería hacer esto.

Me senté y pensé y me di cuenta de que tal vez había demasiadas consultas de inserción al mismo tiempo...
Intenté enviar una solicitud de inserción para la cantidad de datos que la base de datos debería procesar en 1 día. ¡Sucedió!

Bueno, después de eso seguimos enviando solicitudes por la misma cantidad de datos. Como necesitamos eliminar los datos de un mes, repetimos esta operación aproximadamente 35 veces.

Cambiar el nombre de una tabla

Aquí la suerte estuvo de mi lado: todo salió bien.

Alerta desaparecida

La velocidad de procesamiento por lotes ha aumentado.

Anteriormente este proceso tardaba aproximadamente una hora, ahora tarda unos 2 minutos.

Después de estar seguro de que todos los problemas estaban resueltos, eliminé 300 millones de registros. Borré la mesa y me sentí renacido.

Resumen

Me di cuenta de que faltaba el procesamiento de rotación en el procesamiento por lotes, y ese era el principal problema. Este tipo de error arquitectónico conduce a una pérdida de tiempo.

¿Piensa en la carga durante la replicación de datos al eliminar registros de la base de datos? No sobrecarguemos MySQL.

Aquellos que conocen bien las bases de datos definitivamente no encontrarán ese problema. Para el resto de ustedes, espero que este artículo haya sido útil.

¡Gracias por leer!

Estaremos muy contentos si nos dice si le gustó este artículo, si la traducción es clara, si le resultó útil.

Fuente: habr.com

Añadir un comentario