ほとんどの開発チームでは、アプリケーションコードをバージョン管理することは、ごく当たり前に行われています。プルリクエスト、コミット履歴、ブランチ戦略はいずれも標準的な開発手法となっています。しかし、そのアプリケーションを支えるデータベーススキーマは、手作業による変更や簡単なメモ、さらにはチームメンバーの記憶に頼って管理されていることが少なくありません。そのような管理方法では、問題が起きたときや、新しい人が入ったときに対応が難しくなってしまいます。本記事では、スキーマのバージョン管理とは何か、その重要性、そしてNavicatで生成したSQLスクリプトを活用して、スキーマのバージョン管理を開発ワークフローに組み込む方法を解説します。
データベーススキーマのバージョン管理とは
データベーススキーマのバージョン管理とは、テーブル、インデックス、ビュー、ストアドプロシージャ、制約などのデータベース構造を、アプリケーションのソースコードと同様に、Gitなどのバージョン管理システムで厳密に管理することです。スキーマへの変更はすべて、人が読んで理解できるSQLファイルとして個別に記録され、変更内容を説明するコミットメッセージを付けて管理されます。そして、それらはアプリケーションコードと同じリポジトリで一元的に管理されます。
その結果、データベースがどのように変更されてきたのかを記録した、追跡可能な完全な変更履歴を残すことができます。例えば、誰がどのカラムを追加したのか、外部キーがいつ追加されたのか、前回のデプロイ前にはどのようなスキーマだったのかといった内容を確認できます。さらに実務面では、チームのどの開発者でもリポジトリを取得(チェックアウト)するだけで、データベースの最新の構成を正確に把握できるようになります。
ステートベース方式とマイグレーションベース方式
データベーススキーマのバージョン管理には、大きく分けて2つの方式があります。それぞれの違いを理解することで、チームに適した方式を選びやすくなります。
ステートベース方式では、現在のデータベーススキーマ全体を表すSQLファイル(1つ、または複数のファイルで構成される一式)を管理します。スキーマが変更されるたびに、そのファイルを更新して新しいバージョンをコミットします。この方式はシンプルで分かりやすい一方で、既存のデータベースに変更を反映するには、変更後のスキーマと現在のスキーマを比較する必要があります。
マイグレーションベース方式では、スキーマへの変更ごとに、連番付きのマイグレーションスクリプトを作成します。例えば、カラムを追加するスクリプト、インデックスを作成するスクリプト、テーブル名を変更するスクリプトなど、それぞれの変更が独立したファイルとして作成され、順番に適用されます。この方式は管理がやや複雑になるものの、すべての変更履歴を段階的かつ正確に記録できるため、過去のどの時点からでもデータベースを現在の状態まで容易に更新できます。
実際には、多くの開発チームが両者を組み合わせたハイブリッド方式を採用しています。日々の変更はマイグレーションベース方式で管理しながら、定期的にデータベーススキーマ全体を出力したSQLファイルを、参照用のスナップショットとして保存する方法です。
チーム開発において重要な理由
データベーススキーマをバージョン管理していないと、データベースへの変更はチーム内での調整が必要な作業になってしまいます。別々の機能を開発している2人の開発者が、同じテーブルをそれぞれ変更することもあります。また、本番環境には変更が適用されたものの、その内容が記録されず、開発環境のデータベースとの整合性が失われてしまうこともあります。さらに、新しい開発環境を構築しようとしても、現在のスキーマに至るまでにどのような変更が行われたのか、正確に分からなくなってしまいます。
スキーマをバージョン管理することで、これらの問題を解決できます。スキーマの変更はアプリケーションコードと同じレビュー手順で管理され、通常はプルリクエスト、コードレビューを経て、最終的にマージされます。すべての変更は、変更した日時、変更者、変更理由を記したコミットメッセージとともにGitリポジトリへ記録されます。また、どの環境でも、スクリプトを順番に実行するだけで、一から同じ環境を再現できます。
Navicatによるスキーマのバージョン管理ワークフローのサポート
Navicat は、Gitと連携してスキーマのバージョン管理を支援するさまざまなツールを提供しています。これらのツールにより、SQLスクリプトを正確かつ迅速、そして確実に生成できるため、スキーマのバージョン管理ワークフローで最も手間がかかりやすい作業を効率化できます。
最も手軽な方法は、SQLファイルにダンプ機能を利用することです。この機能では、テーブル、ビュー、関数、ストアドプロシージャなどのデータベースオブジェクトを定義するDDL(データ定義言語)を、通常のSQLファイルとして出力できます。出力したファイルは、そのままデータベーススキーマ全体のスナップショットとしてGitリポジトリに追加できます。ステートベース方式では、多くの場合これだけで十分です。スキーマを変更したら、SQLファイルを出力し、更新したファイルをコミットします。
マイグレーションベース方式では、構造の同期ツールの方が適しています。このツールは、例えば開発環境のデータベースと本番公開前の最終確認を行うステージング環境のデータベースを並べて比較し、構造上の違いを検出するとともに、対象のデータベースを元のデータベースと同じ構造にするためのSQLスクリプトを生成します。ALTER TABLE文を手作業で作成する代わりに、Navicatのビジュアルテーブルデザイナーで開発環境のスキーマを変更し、その後、構造の同期を使用してマイグレーションスクリプトを自動生成できます。生成されたSQLスクリプトは、そのままレビューとコミットを行う次の連番付きマイグレーションファイルとして利用できます。
Navicat Data Modelerは、スキーマを視覚的に設計してから実装するチーム向けに、新たな選択肢を提供します。物理モデルの作成後は、モデルをSQL/スクリプトファイルにエクスポート機能を使用して、モデル化したスキーマ全体の作成用SQLスクリプトを生成できます。また、参照整合性ルール、コメント、文字セットなど、出力する項目を細かく指定することも可能です。生成されたSQLファイルは、一貫性があり、そのままGitリポジトリへコミットしたり、新しいデータベースに対して実行したりすることができます。
これらのワークフローに共通する基本的な考え方は同じです。Navicatは、視覚的に設計したスキーマや現在のデータベースの状態を、Gitでバージョン管理できるSQLへ変換する役割を担います。そのため、バージョン管理がもたらす変更履歴の追跡やチームでの共同作業といった利点を損なうことなく、画面上でスキーマを視覚的に設計するワークフローも採り入れられます。
結論
データベーススキーマのバージョン管理を始めるために、チームの開発プロセスを大きく変える必要はありません。Gitリポジトリ内にスキーマ用のフォルダを作成し、スキーマのSQLスクリプトをコミットすることから始めれば十分です。NavicatのSQLスクリプト生成機能や構造同期機能を利用して、これらのSQLスクリプトを一貫した形式で生成すれば、手作業による負担を減らし、スキーマのバージョン管理が継続しやすくなります。また、データベースの変更履歴も、アプリケーションコードと同じように分かりやすく管理できるようになります。

