はじめに
別々の Docker コンテナで動いている MySQL データベース同士のスキーマを比較したい場面があります。
本記事では mysqldump と diff を使ったシンプルな方法を紹介します。
検証環境の構築
ディレクトリ構成
mysqldiff-demo/
├── docker-compose.yml
└── init/
├── db1/
│ └── 01_schema.sql
└── db2/
└── 01_schema.sql
docker-compose.yml
version: '3.8'
services:
db1:
image: mysql:8.0
container_name: mysqldiff-db1
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: testdb
ports:
- '3306:3306'
volumes:
- ./init/db1:/docker-entrypoint-initdb.d
networks:
- db-network
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 10s
timeout: 5s
retries: 5
db2:
image: mysql:8.0
container_name: mysqldiff-db2
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: testdb
ports:
- '3307:3306'
volumes:
- ./init/db2:/docker-entrypoint-initdb.d
networks:
- db-network
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 10s
timeout: 5s
retries: 5
networks:
db-network:
driver: bridge
初期化 SQL
意図的に差分を作るため、2 つの DB で異なるスキーマを定義します。
init/db1/01_schema.sql
USE testdb;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
init/db2/01_schema.sql
USE testdb;
-- users: phone カラムを追加
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
phone VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- products: description を追加、stock を削除
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- DB2 にのみ存在するテーブル
CREATE TABLE reviews (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
user_id INT NOT NULL,
rating INT NOT NULL,
comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
起動
cd mysqldiff-demo
docker-compose up -d
テーブルが作成されたかを確認します。
docker exec mysqldiff-db1 mysql -u root -prootpass -e "SHOW TABLES FROM testdb;"
docker exec mysqldiff-db2 mysql -u root -prootpass -e "SHOW TABLES FROM testdb;"
スキーマ比較の実行
mysqldump でスキーマをダンプ
docker exec mysqldiff-db1 mysqldump -u root -prootpass --no-data testdb > db1_schema.sql
docker exec mysqldiff-db2 mysqldump -u root -prootpass --no-data testdb > db2_schema.sql
--no-data オプションでスキーマのみ(データなし)をダンプします。
diff で比較
diff -u db1_schema.sql db2_schema.sql
実行結果
--- db1_schema.sql
+++ db2_schema.sql
@@ -47,14 +47,36 @@
CREATE TABLE `products` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL,
+ `description` text,
`price` decimal(10,2) NOT NULL,
- `stock` int DEFAULT '0',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+CREATE TABLE `reviews` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `product_id` int NOT NULL,
+ `user_id` int NOT NULL,
+ `rating` int NOT NULL,
+ `comment` text,
+ `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ ...
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `users` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`email` varchar(255) NOT NULL,
+ `phone` varchar(20) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
検出された差分
| テーブル | 差分内容 |
|---|---|
users |
DB2 に phone カラム追加 |
products |
DB2 に description 追加、stock 削除 |
reviews |
DB2 にのみ存在 |
まとめ
今回はサクッとシンプルにやりたかったのでmysqldump と diff を使った方法を取りましたが、大規模環境や自動化が必要な場合は他のツールが有効になってくるかと思います。
お試しや小さい環境で軽く比較をしたいときに参考にしてみてください。