¿Mejores prácticas para cambios de esquema y migraciones de datos a una base de datos en vivo sin tiempo de inactividad?

43

¿Cómo se realizan cambios de esquema en una base de datos en vivo sin tiempo de inactividad?

Por ejemplo, supongamos que tengo una base de datos PostgreSQL con una tabla que incluye varios datos de usuario, como direcciones de correo electrónico, etc., todos asociados con usuarios específicos. Si quisiera mover las direcciones de correo electrónico a una nueva tabla dedicada, tendría que cambiar el esquema y luego migrar los datos del correo electrónico a la nueva tabla. ¿Cómo podría hacerse esto sin detener las escrituras en la tabla original? Seguramente, mientras los datos se escriben desde la tabla anterior a la nueva, los datos nuevos se seguirán escribiendo en la tabla anterior y se perderán, ¿verdad?

Supongo que este problema surge con bastante frecuencia, pero no puedo encontrar ninguna solución estándar para tratarlo.

Este artículo aborda el problema, pero realmente no entendí el paso 3. Dice que escriba en ambas tablas y luego migre los datos antiguos de la primera tabla a la nueva. ¿Cómo se asegura de que solo está migrando datos antiguos?

(Yo uso PostgreSQL en Heroku ).

Dan Leary
fuente
2
Facebook desarrolló una herramienta para hacer esto para MySQL.
Nick Chammas
2
K. Scott Allen escribió sobre un sistema para administrar versiones de esquema aquí . Creé DbUpdater, una herramienta de código abierto para la implementación de esquemas compatibles con la versión. Más aquí - http://www.tewari.info/dbupdater
ceniza
@ NickChammas Gracias por compartir eso. Tengo muchas preguntas al respecto. ¿Podría sugerir un tutorial más detallado, preferiblemente un video, que explique cosas como bit log, índices no agrupados y responda preguntas como: 1. Cómo seleccionar datos de la tabla de origen en un archivo externo reducirá la carga en comparación con copiar a destino mesa directamente. 2. ¿Cuándo terminará la fase de copia? Estas son solo algunas preguntas que tengo y solo he comenzado a leerlas.
Sandeepan Nath
@SandeepanNath - Lo siento, no estoy tan familiarizado con la herramienta de Facebook y, por lo tanto, no puedo señalarle más recursos. Leí un anuncio al respecto y publiqué mi comentario hace años, pero nunca lo he usado.
Nick Chammas

Respuestas:

27

Ya casi tienes tu respuesta:

  1. Crea la nueva estructura en paralelo
  2. Comienza a escribir en ambas estructuras
  3. Migrar datos antiguos a la nueva estructura.
  4. Solo escribe y lee nueva estructura
  5. Eliminar columnas antiguas

En cuanto al paso 3 , use algo como esto (en una transacción):

Inserte lo que aún no está allí:

INSERT INTO new_tbl (old_id, data)
SELECT old_id, data
FROM   old_tbl
WHERE  NOT EXISTS (SELECT * FROM new_tbl WHERE new_tbl.old_id = old_tbl.old_id);

Actualice lo que ha cambiado mientras tanto:

UPDATE new_tbl
SET    data  = old.data
USING  old_tbl
WHERE  new_tbl.old_id = old_tbl.old_id
AND    new_tbl.data IS DISTINCT FROM old_tbl.data;

No se tocarán nuevos datos, porque son idénticos en ambos lugares.

Erwin Brandstetter
fuente
Tengo algunas preguntas al tratar de comprender el escenario para el que propuso esta respuesta: 1. ¿Se implementarán los cambios en el código junto con el inicio de los cambios de db? 2. ¿Por qué será necesario escribir a ambas estructuras? 3. ¿Por qué no se puede abrir la nueva estructura primero y luego se migran los datos existentes y luego se implementan los cambios de código que llenarán la nueva estructura? 4. ¿Por qué es necesario averiguar qué no está allí (su primera consulta)? ¿Estás proponiendo la inserción en múltiples intentos?
Sandeepan Nath
2
@SandeepanNath, para responder la pregunta 3 en su comentario: porque si (a) muestra una nueva estructura, (b) migra datos a ella, (c) cambia su código para escribir datos en la nueva estructura en lugar de la anterior, entonces todos datos de los cambios hechos entre la etapa b y la etapa c sólo existirá en la antigua estructura. La pregunta era cómo hacer cambios de esquema sin tiempo de inactividad. Lea esta respuesta nuevamente, cuidadosamente.
Comodín