Modificación de columnas de tablas mysql muy grandes con poco o ningún tiempo de inactividad

18

Periódicamente necesito hacer cambios en las tablas en mysql 5.1, principalmente agregando columnas. Muy simple con el comando alter table. Pero mis tablas tienen hasta 40 millones de filas ahora y están creciendo rápidamente ... Por lo tanto, los comandos de alterar tabla tardan varias horas. Supongo que en un par de meses tardarán días.

Como estoy usando Amazon RDS, no puedo tener servidores esclavos para jugar y luego pasar a dominar. Entonces, mi pregunta es si hay una manera de hacer esto con un tiempo de inactividad mínimo. No me importa que una operación tarde horas o incluso días si los usuarios aún pueden usar la base de datos, por supuesto ... ¿Pueden al menos leer mientras se agregan columnas? ¿Qué sucede si mi aplicación intenta escribir? Insertar o actualizar? Si falla de inmediato, eso no es tan malo, si simplemente se cuelga y causa problemas para el servidor de db, eso es un gran problema.

Este debe ser un problema de escala bastante común, todos deben agregar columnas. ¿Qué se suele hacer con una base de datos de producción? Esclavo -> maestro de migración?

Actualización : olvidé mencionar que estoy usando el motor de almacenamiento innodb

apptree
fuente
1
En caso de que alguien siga buscando una respuesta ... blog.staginginstance.com/… ^^
anónimo el

Respuestas:

10

Periódicamente necesito hacer cambios en las tablas en mysql 5.1, principalmente agregando columnas.

No lo hagas No realmente. Solo no lo hagas. Debe ser una ocasión muy raro cuando se trata siempre es necesario.

Suponiendo que sus datos realmente estén normalizados para comenzar, la forma correcta de resolver el problema es agregar una nueva tabla con una relación 1: 1 a la tabla base (no obligatorio en la nueva tabla).

Tener que agregar columnas regularmente suele ser un indicador de una base de datos que no está normalizada: si su esquema no está normalizado, entonces ese es el problema que debe solucionar.

Finalmente, si su esquema realmente está realmente normalizado y realmente, realmente debe seguir agregando columnas, entonces:

  1. Asegúrese de tener una columna de marca de tiempo en la base de datos o que esté generando registros de replicación
  2. Crear una copia (B) de la tabla (A)
  3. agregue las nuevas columnas a B (esto todavía se bloqueará con myisam)
  4. deshabilitar transacciones
  5. renombrar la tabla original (A) como otra cosa (copia de seguridad)
  6. cambie el nombre de la nueva tabla (B) con el nombre de la tabla original (A)
  7. reproducir las transacciones desde el inicio de la operación desde el registro de replicación o desde la tabla de respaldo
  8. permitir transacciones.
symcbean
fuente
2
Gracias por su enfoque paso a paso. ¿Es realmente raro modificar tablas? Entiendo que en su lugar puedo agregar otra tabla con la nueva columna (en el caso de que necesite agregar una columna) y hacer que haga referencia a la tabla grande original en una relación 1: 1. Pero no parece correcto tener 15 tablas 1: 1 muy grandes cuando todas deberían estar en 1 tabla ... Por supuesto, el rendimiento de las consultas también sufre, por no mencionar los problemas de indexación. No soy un experto, pero mi base de datos está bastante bien normalizada y parece natural que tenga que modificar periódicamente ..
apptree
2
"¿Es realmente raro modificar tablas?" - Si.
symcbean
1
No, pero se puede argumentar que si eso sucede REGULARMENTE, no como parte de una importante actualización de software, entonces alguien debe ser despedido por no darse cuenta de que todas las tablas deberían estar allí en primer lugar. El problema / truco aquí es "regularmente", no "Una vez cada dos meses".
TomTom
22
Como desarrollador, especialmente uno que trabaja en empresas nuevas y jóvenes, no podría estar menos de acuerdo con symcbean y @TomTom. Las cosas cambian, los productos cambian, los objetivos comerciales cambian y la estructura de la base de datos debe cambiar con ellos. Brindar un buen servicio de DBA significa decir "sí" a esos cambios, y luego descubrir cómo implementarlos de manera eficiente. Las bases de datos altamente normalizadas son un concepto que murió hace mucho tiempo. Dan como resultado un mal rendimiento y ciclos de desarrollo lentos.
pents90
44
¿Poco común para cambiar tablas? Tal vez en grandes empresas, pero en un equipo ágil que sucede con bastante frecuencia, los requisitos cambian ...
tibo
12

Solo tuve que hacer esto recientemente. Lo que Amazon recomendó fue usar el Kit de herramientas de Percona. Lo descargué y pude ejecutar algo como:

./pt-online-schema-change h=databasenameHostName,D=databasename,t=tablename --recursion-method=none --execute --user username --password password --alter "MODIFY someColumn newDataType"

y funciona muy bien Le indica cuánto tiempo le queda en el proceso.

Realmente crea una nueva tabla con la nueva columna y luego copia los datos existentes. Además, crea un activador para que los nuevos datos también se transfieran a la nueva tabla. Luego cambia el nombre de las tablas de forma automática, elimina la tabla anterior y ya está en funcionamiento con la nueva columna y sin tiempo de inactividad mientras esperaba las actualizaciones.

libertad
fuente
El equipo de Percona tiene una breve reseña sobre cómo habilitar la función log_bin_trust_function_creators, a través de grupos de parámetros RDS (ya que SET GLOBAL log_bin_trust_function_creators = 1 no funciona en RDS), requerido por la herramienta pt-online-schema-change. Más detalles: percona.com/blog/2016/07/01/pt-online-schema-change-amazon-rds
usuario1652110
funcionó para mí
Adiii
4

symcbean proporciona algunas recomendaciones sólidas .

Para responder a su pregunta, la mejor y más fácil forma de mitigar el impacto es replicar varias bases de datos. Doble maestro con un procedimiento de conmutación por error apropiado que detiene la replicación en el activo, lo que permite una alteración en el inactivo sin afectar el activo.

Potencialmente, podría hacer esto en una única base de datos en vivo y minimizar el impacto utilizando un procedimiento similar al que detallé en esta respuesta . Es cierto que esto es similar a lo que describió symcbean pero incluye detalles técnicos. También podría usar un campo auto_increment y no solo la marca de tiempo.

En última instancia, si su conjunto de datos está creciendo tanto, también debe considerar el archivo entre las bases de datos OLTP y OLAP . Su conjunto de datos de transacciones no debería ser tan grande, si diseña adecuadamente.

Warner
fuente
2

Del manual: http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

En la mayoría de los casos, ALTER TABLE hace una copia temporal de la tabla original. MySQL incorpora la alteración en la copia, luego elimina la tabla original y renombra la nueva. Mientras se ejecuta ALTER TABLE, otras tablas pueden leer la tabla original. Las actualizaciones y las escrituras en la tabla se detienen hasta que la nueva tabla esté lista, y luego se redirigen automáticamente a la nueva tabla sin ninguna actualización fallida.

Entonces, la lectura funcionará bien. Las escrituras se estancarán, pero se ejecutarán después. Si desea evitar esto, deberá modificar su software.


fuente
Así que hice esto y deshabilité las partes de mi sitio que escriben en la tabla que estoy modificando en este momento. Hasta ahora he recibido varias excepciones de "Tiempo de espera de bloqueo excedido; intente reiniciar la transacción", eso no es tan malo. Sin embargo, estaban en operaciones de lectura PURELY ...
apptree
0

Estoy en una situación similar en la que tengo que alterar 1 de mi tabla de transacciones, que es de casi 65 GB. Escucho 2 soluciones

  1. Use ALTER directo y déjelo correr (X números de horas o días)
  2. Asegúrese de tener una columna de marca de tiempo en la base de datos o que esté generando registros de replicación
    • Crear una copia (B) de la tabla (A)
    • agregue las nuevas columnas a B (esto todavía se bloqueará con myisam)
    • deshabilitar transacciones
    • renombrar la tabla original (A) como otra cosa (copia de seguridad)
    • cambie el nombre de la nueva tabla (B) con el nombre de la tabla original (A)
usuario144107
fuente