sql >> Base de Datos >  >> RDS >> Mysql

Laravel 5.5 Consolidar migraciones con base de datos de producción

Después de un par de intentos de solución excesivamente ingeniosos y excesivamente ingeniosos, creo que la siguiente es una solución viable para el problema.

tl;dr:

  • Migraciones de sujetalibros a ambos lados de las migraciones que crean el esquema desde cero.
  • Actualizar proyecto.
  • Migrar.
  • Elimine los sujetalibros y todas las migraciones anteriores.
  • Eliminar registros de migrations mesa.

El primer sujetalibros cambia el nombre de las tablas afectadas. El segundo sujetalibros copia los datos de las tablas renombradas a las tablas nuevas y luego elimina las tablas renombradas.

Nota:puedes hacer lo que quieras dentro de los sujetalibros, esto es solo un mínimo.

Entonces, digamos algo como lo siguiente para las migraciones:

  • 2017_09_05_000000_create_some_table.php
  • 2017_09_05_000001_add_field_x_to_some_table.php
  • 2017_09_05_000002_add_field_y_to_some_table.php
  • 2017_09_05_000003_add_field_z_to_some_table.php

Crearíamos otra migración:

  • 2017_09_05_000004_pre_refresh.php

Crearíamos otra migración basada en el conocimiento que tenemos ahora:

  • 2017_09_05_000005_create_some_table.php

Crearíamos el último sujetalibros, donde se producirá la migración de datos:

  • 2017_09_05_000006_post_refresh.php

Las primeras cuatro migraciones no se ejecutarán porque ya lo han hecho.

/** 2017_09_05_000004_pre_refresh.php */
class PreRefresh extends Migration
{
    public function up()
    {
        $prefix = 'zz_';
        $tablesToRename = [
            'foos',
            'bars'
        ];

        foreach($tablesToRename as $table) {
            Schema::rename($table, $prefix . $table);
        }
    }
}

No hay necesidad de un pago inicial, porque este es un trato único. Esto se ejecutará primero, lo que debería dar como resultado que se cambie el nombre de todas las tablas enumeradas en la matriz. Luego se ejecutarán las migraciones consolidadas (optimizadas).

/** 2017_09_05_000006_post_refresh.php */
class PostRefresh extends Migration
{
    public function up()
    {
        // Do what you need to do.
        // If you cannot use your models, just use DB::table() commands.

        $foos = DB::table('zz_foos')->get();
        foreach ($foos as $foo) {
            DB::table('foo')->insert([
                    'id'         => $foo->id,
                    'created_at' => $foo->created_at,
                    'updated_at' => $foo->updated_at
                ]);
        }

        $bars = DB::table('zz_bars')->get();
        foreach ($bars as $bar) {
            DB::table('bar')->insert([
                    'id'         => $bar->id,
                    'created_at' => $bar->created_at,
                    'updated_at' => $bar->updated_at,
                    'foo_id'     => $bar->foo_id
                ]);
        }

        // Tear down.
        $prefix = 'zz_';
        $tablesToRename = [
            'foo',
            'bar'
        ];

        foreach ($tablesToRename as $table) {
            DB::statement('SET FOREIGN_KEY_CHECKS=0');
            Schema::dropIfExists($prefix . $table);
            DB::statement('SET FOREIGN_KEY_CHECKS=1');
        }
    }
}

Después de ejecutar esto, puede eliminar todas sus migraciones desde pre_refresh y previo. Así como el post_refresh . Luego puedes dirigirte a las migrations tabla y elimine las entradas para esas migraciones.

Eliminar las entradas no es del todo necesario, pero si migrate:rollback recibirá mensajes de error que indican que no se puede encontrar la migración.

Advertencias

  1. Si la arquitectura no es modular por diseño, puede resultar bastante engorrosa. Sin embargo, si ha separado su código en servicios, parece ser un poco más fácil.
  2. El manejo de errores de Laravel y los mensajes durante las migraciones son muy limitados; por lo tanto, la depuración podría ser difícil.
  3. Recomendamos encarecidamente comenzar con las tablas más estables en su aplicación o servicio. Además, comenzar con aquellos que son fundamentales para su aplicación también podría resultar beneficioso.

Nota:Cuando realmente hago esto en producción, no solo en mi local (una y otra vez), y si no hay una mejor respuesta, aceptaré esto.

Consideraciones

Si divide su aplicación en proveedores de servicios con migraciones discretas, puede comentar el proveedor de servicios en /config/app cuando ejecutas las migraciones. De esta manera, crea un lote para el servicio ahora con línea base. Entonces, supongamos que tiene las siguientes migraciones donde cada letra representa una migración y cada letra duplicada representa el mismo servicio:

  • A
  • B
  • C
  • A
  • C
  • B
  • A

Después de consolidar el servicio A:

  • B
  • C
  • C
  • B
  • A

Después de consolidar B:

  • C
  • C
  • A
  • B

Después de consolidar C:

  • A
  • B
  • C

actualizar

54 migraciones hasta 27 hasta ahora. Incluso saqué algunos cambios de esquema de grandes up() y down() métodos y hacerlos migraciones separadas. El buen efecto secundario aquí son los lotes. Migré comenzando con las tablas base sobre las que se admite todo lo demás; por lo tanto, retroceder es más servicio por servicio.