Introducción
Hola. Soy ningenMe, desarrollador web.
Como se menciona en el título, mi historia es sobre la eliminación física de 300 millones de registros en MySQL.
Me interesó esto, así que decidí hacer un recordatorio (instrucción).
Inicio — Alerta
En el procesamiento por lotes servidor, que utilizo y mantengo, hay un proceso regular que una vez al día recopila datos del último mes de MySQL.
Normalmente, este proceso termina aproximadamente en 1 hora, pero esta vez no finalizaba en 7 u 8 horas, y la alerta seguía apareciendo...
Busca la causa
Intenté reiniciar el proceso, revisar los registros, pero no vi nada alarmante.
La consulta se indexó correctamente. Pero cuando pensé en qué podría estar mal, 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. Parece que la indexación funcionó correctamente, solo que muy lenta.
Los datos requeridos para el mes eran alrededor de 12 000 000 de 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 aumenta aproximadamente en 400 000 registros cada día. La base de datos solo debería haber recopilado datos del último mes, por lo tanto, el cálculo fue para que pudiera manejar exactamente este volumen de datos, pero, desafortunadamente, la operación rotate no estaba habilitada.
Esta base de datos no fue diseñada por mí. La tomé de otro desarrollador, así que me quedó la sensación de que es una deuda técnica.
Llegó un momento en que el volumen de datos insertados diariamente se hizo grande y finalmente alcanzó su límite. Se supone que al trabajar con un gran volumen de datos, deberían dividirse, pero desafortunadamente, eso no se hizo.
Y ahí es donde entré yo.
Corrección
Era más razonable reducir la base de datos en sí y acortar el tiempo de procesamiento que cambiar la lógica misma.
La situación debería cambiar significativamente si eliminara 300 millones de registros, así que decidí hacerlo… Ah, pensé que definitivamente funcionaría.
Acción 1
Después de preparar una copia de seguridad confiable, finalmente comencé a enviar las consultas.
「Enviando consulta」
DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';「…」
「…」
“Hmm... No hay respuesta. ¿Puede que el proceso esté tardando mucho tiempo?” — pensé, pero por si acaso miré en grafana y vi que la carga del disco estaba aumentando rápidamente.
«Es peligroso» — pensé una vez más y detuve la solicitud de inmediato.
Acción 2
Después de analizar todo, me di cuenta de que el volumen de datos era demasiado grande para eliminarlo todo de una vez.
Decidí escribir un script que pudiera eliminar alrededor de 1,000,000 de registros y lo lancé.
「Voy a implementar el script」
“Ahora definitivamente funcionará”, pensé.
Acción 3
El segundo método funcionó, pero resultó ser muy laborioso.
Para hacerlo todo de manera ordenada y sin nervios de más, se necesitarían alrededor de dos semanas. Sin embargo, este escenario no cumplía con los requisitos del servicio, por lo que tuve que abandonarlo.
Por eso, esto es lo que decidí hacer:
Copiar la tabla y renombrarla
Del paso anterior, entendí que eliminar un volumen tan grande de datos genera una carga igual de grande. Por lo tanto, decidí crear una nueva tabla desde cero usando ‘insert’ y mover a ella los datos que planeaba eliminar.
| hoge_table | 350'000'000|
| tmp_hoge_table | 50'000'000|Si se crea una nueva tabla del mismo tamaño que se indica arriba, la velocidad de procesamiento de datos también debería aumentar en 1/7.
Después de crear la tabla y renombrarla, comencé a utilizarla como tabla maestra. Ahora, si elimino la tabla con 300 millones de registros, todo debería estar bien.
Descubrí que ‘truncate’ o ‘drop’ generan menos carga que ‘delete’ y decidí usar este método.
Ejecución
「Enviando consulta」
INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS'; 「…」
「…」
「¿eh…?」
Acción 4
Pensé que la idea anterior funcionaría, pero después de enviar la solicitud de ‘insert’, apareció un error múltiple. MySQL no perdona.
Ya estaba tan cansado que empecé a pensar que no quería hacer esto más.
Me senté a pensar y comprendí que, tal vez, para una sola vez, había demasiadas solicitudes de ‘insert’...
Intenté enviar una solicitud de ‘insert’ para un volumen de datos que la base de datos debería procesar en un día. ¡Funciona!
Y después de eso, seguimos enviando solicitudes para el mismo volumen de datos. Como hay que eliminar el volumen mensual de datos, repetimos esta operación unas 35 veces.
Renombrar la tabla
Aquí la suerte estuvo de mi lado: todo salió bien.
La alerta desapareció.
La velocidad de procesamiento por lotes aumentó.
Antes, este proceso tardaba alrededor de una hora, ahora toma aproximadamente 2 minutos.
Después de asegurarme de que se resolvieron todos los problemas, eliminé 300 millones de registros. Borré la tabla y me sentí como renacido.
Resumen
Me di cuenta de que se había pasado por alto el procesamiento de rotación en el procesamiento por lotes, y esa era la principal problemática. Tal error en la arquitectura resulta en una pérdida de tiempo inútil.
¿Alguna vez piensas en la carga durante la 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 no enfrentarán este problema. A los demás, espero que este artículo les haya sido útil.
¡Gracias por leer!
Estaríamos muy contentos si nos dijeras si te gustó este artículo, si la traducción fue clara y si te fue útil.
Fuente: habr.com
