La historia de eliminar físicamente 300 millones de registros en MySQL

Introducción



Oye. Soy ningenMe, desarrollador web.



Como dice el título, mi historia trata sobre la eliminación física de 300 millones de registros en MySQL.



Me interesé en esto, así que decidí hacer un memo (instrucción).



Inicio - Alerta



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



Por lo general, 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 salir ...



Buscando una razón



Intenté reiniciar el proceso, miré los registros, pero no vi nada terrible.

La solicitud se indexó correctamente. Pero cuando me pregunté qué 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 parece funcionar correctamente, solo que muy lenta.



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



DB



Básicamente, es una tabla que crece alrededor de 400.000 registros cada día. Se suponía que la base de datos recopilaría datos solo durante el último mes, por lo tanto, el cálculo se basó en el hecho de que resistirá 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í. Tomé el relevo de otro desarrollador, así que sentí que era una deuda técnica.



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



Y luego entré.



Corrección



Era más racional reducir la propia base de datos y reducir el tiempo de procesamiento que cambiar la lógica en sí.



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



Paso 1



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



「Enviar una solicitud」



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


「...」



「...」



“Hmm… No hay respuesta. ¿Quizás el proceso está tardando mucho? " - pensé, pero por si acaso miré en grafana y vi que la carga del disco estaba creciendo muy rápido.

"Peligroso" - pensé de nuevo e inmediatamente detuve la solicitud.



Paso 2



Después de analizar todo, me di cuenta de que la cantidad de datos era demasiado grande para eliminar todo de una vez.



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



「Implemento el script」



"Ahora definitivamente funcionará", pensé



Paso 3



El segundo método funcionó, pero resultó ser muy lento.

Para hacer todo de forma ordenada, sin nervios adicionales, se necesitarían unas dos semanas. Pero aún así, este escenario no cumplía con los requisitos del servicio, por lo que tuve que alejarme de él.



Por lo tanto, esto es lo que decidí hacer:



Copie la tabla y cambie el nombre



En el paso anterior, me di cuenta de que eliminar una cantidad tan grande de datos crea una carga igualmente grande. Por lo tanto, decidí crear una nueva tabla desde cero usando insertar y mover 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 el anterior, la velocidad de procesamiento 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 una tabla con 300 millones de registros, todo debería estar bien.

Descubrí que truncar o soltar es menos general que eliminar y decidí usar ese método.



Actuación



「Enviar una solicitud」



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


「...」

「...」

「uh ...?」



Paso 4



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



Ya estaba tan cansado 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 solicitudes de inserción por una vez ...

Traté de enviar una solicitud de inserción por la cantidad de datos que la base de datos debería procesar en 1 día. ¡Ocurrió!



Bueno, después de eso, continuamos enviando solicitudes por la misma cantidad de datos. Dado que necesitamos eliminar la cantidad mensual de datos, repetimos esta operación unas 35 veces.



Cambiar el nombre de una tabla



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



Alerta desaparecida



Ha aumentado la velocidad de procesamiento por lotes.



Anteriormente, este proceso demoraba aproximadamente una hora, ahora toma aproximadamente 2 minutos.



Después de convencerme de que todos los problemas se resolvieron, eliminé 300 millones de registros. Borré la mesa y me sentí renacer.



Resumiendo



Me di cuenta de que el procesamiento por rotación se pasaba por alto en el procesamiento por lotes y ese era el problema principal. Este error arquitectónico es una pérdida de tiempo.



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



Aquellos que están bien versados ​​en bases de datos definitivamente no enfrentarán este problema. Por lo demás, espero que este artículo haya sido útil.



¡Gracias por leer!



Estaremos muy contentos si nos dices si te gustó este artículo, fue clara la traducción, te fue útil?



All Articles