Laravel 8 の新機能！マイグレーションスカッシングで肥大化したマイグレーションファイルを1つにまとめる

大規模または長期間運用されているアプリケーションでは、
数年以上前に作成されたマイグレーションファイルが膨大な数になってきます。

データベーステストを行っているプロジェクトでは、マイグレーションを適用するのに時間がかかりテストの速度が低下する懸念があります。
これの解決策として、Laravel 8ではマイグレーションスカッシング(スキーマダンプ)と呼ばれる新機能が追加されました。

`mysqldump` まはた `pgdump` を使用して現在のスキーマの状態からダンプを作成します。
(MySQL、PostgreSQL、SQLiteデータベースのみサポート)

## 公式ドキュメント・ソース

- https://readouble.com/laravel/8.x/ja/migrations#squashing-migrations
- https://laravel.com/api/8.x/Illuminate/Database/Console/DumpCommand.html
- https://github.com/laravel/framework/blob/8.x/src/Illuminate/Database/Console/DumpCommand.php

## マイグレーションファイルを確認

初期状態のままですが...下記のマイグレーションファイルがあるとします。

```
$ ls -1 database/migrations
2014_10_12_000000_create_users_table.php
2014_10_12_100000_create_password_resets_table.php
2019_08_19_000000_create_failed_jobs_table.php
```

## スキーマダンプ コマンド


```shell-session
$ php artisan schema：dump
```

`--prune` オプションを付けると、既存のマイグレーションファイルの削除が行われます。

```shell-session
$ php artisan schema：dump --prune
```

`database/schema/mysql-schema.sql` が生成されます。
`/database/schema/<DB_CONNECTION>-schema.mysql`

```sql:database/schema/mysql-schema.sql
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `failed_jobs` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `migrations` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `batch` int NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `password_resets` (
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  KEY `password_resets_email_index` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email_verified_at` timestamp NULL DEFAULT NULL,
  `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

INSERT INTO `migrations` VALUES (1,'2014_10_12_000000_create_users_table',1);
INSERT INTO `migrations` VALUES (2,'2014_10_12_100000_create_password_resets_table',1);
INSERT INTO `migrations` VALUES (3,'2019_08_19_000000_create_failed_jobs_table',1);
```

`migrations` 以外のテーブルのデータはダンプされず、テーブル構成のみダンプされるみたいです。(マイグレーションなのにデータまでダンプされたら困りますが...)

## マイグレーションを実行する

```shell-session
$ php artisan migrate:reset
$ php artisan migrate
Loading stored database schema: /Users/ucan-lab/laravel-love/backend/database/schema/mysql-schema.sql
Loaded stored database schema. (128.57ms)
Nothing to migrate.
```

`mysql-schema.sql` が読み込まれて、既存のマイグレーションファイルは無視されてます。

## スキーマダンプのメリット

前述の通り、データベーステストが高速化されるメリットがあります。

また、スキーマダンプはマイグレーションファイルではなく `mysqldump` コマンドを使って現在のデータベースからダンプファイルを作成されています。
本来の用途とは違うかもしれませんが、マイグレーションファイルでデータベースが管理されていないプロジェクトからLaravelに移行する際はとても役に立つ機能ではないでしょうか。

## 使ってみた感想

`mysqldump` コマンドをLaravelで実行しているので、Dockerでやろうとすると`mysqldump`コマンドをコンテナ内で使えるようにしてあげる必要があるし、debianの`default-mysql-client`はMariaDBに統合されたようでLaravelで実行しているオプションが存在していなかったりとDockerで頑張ろうとすると手間かもしれません...今回はローカルで試してみました。

## 参考

- https://readouble.com/laravel/8.x/ja/migrations#squashing-migrations
- https://robindirksen.nl/blog/laravel-schema-dump-how-to-speed-up-your-migrations
- https://github.com/laravel/framework/pull/32275