メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
MariaDB と MySQL は同じワイヤプロトコルと、SQL 構文の大部分を共有しています。そのため、移行は見かけ上は単純です。ダンプして、ロードするだけです。実際には、MariaDB 固有の型、オブジェクト、およびダンプの動作のいくつかが、プレーンなロードを途中で止めます。そのうちの 1 つは、エラーをまったく出さずに列の格納型を変えてしまいます。このガイドでは、MariaDB 12.3.3 から取得して MySQL にロードした実際のダンプに基づき、実際に何が壊れ、どう修正するかを説明します。

データ型とデフォルトの違い

MariaDB 固有のスキーマオブジェクトがロードを失敗させる

CREATE SEQUENCE を使うスキーマは、MySQL にロードすると、どのテーブルも作成される前に即座に失敗します。mysqldump はシーケンスの定義をテーブルより先に書き込むためです。シーケンスを含む未修正のダンプをロードすると次のようになります。at line N の値はステートメントがダンプ内のどこにあるかを示すもので、ここに示す数値とは一致しません。
ダンプから DROP SEQUENCE / CREATE SEQUENCE / DO SETVAL(...) のブロックを削除し、DEFAULT nextval(...) と書かれた列のデフォルトを、プレーンな AUTO_INCREMENT 列またはアプリケーションが割り当てる値に置き換えます。 INET6 型の列も、同じロードの後の方で、ローダーがその列を宣言するテーブルに到達した時点で同じように失敗します。これは、このガイドの中で、どのサーバーにロードするかによって文言が変わる唯一のエラーです。VillageSQL は型の名前を示します。その文法はその位置でカスタム型名を受け入れるため、解決できなかった型を報告するからです。
標準の MySQL 8.4 は、同じステートメントを代わりに一般的な構文エラーで拒否します。
どちらも ERROR 1064 で、どちらも問題の行を示すため、修正はどちらでも同じです。ロードの前に列の型を VARCHAR(45)(テキスト形式の IPv6 アドレスに十分な長さ)に変更するか、移行先に拡張機能がインストールされていれば、それが提供する INET 型に変更します。

外部キー制約名がテーブル間で衝突する

MariaDB の mysqldump は、名前のない外部キー制約に、テーブルごとに 1 から始まるプレーンな整数の名前を自動で付けます。同じスキーマ内の 2 つのテーブルが、どちらも文字どおり 1 という名前の制約を持つことがあります。
MySQL は、外部キー制約名がテーブル内だけでなく、スキーマ全体で一意であることを要求します。2 つ目の CONSTRAINT 1“ のロードは次のエラーで失敗します。
これは、元のテーブルが MariaDB の自動命名に頼っていた(CREATE TABLE で CONSTRAINT name を指定していなかった)場合にだけ起こります。ロードの前に、衝突する各制約を一意な名前、たとえば order_items_ibfk_1 と orders_ibfk_1 に変更します。

JSON 列はエラーなしに、別の型としてロードされる

上の 3 つの問題とは異なり、JSON 列はエラーも警告もなく MySQL にロードされます。MariaDB の JSON 列について、ダンプされた CREATE TABLE は次のようになります。
MySQL は CHECK 制約と JSON_VALID() 関数をサポートしているため、このステートメントは書かれたとおりに実行されます。MySQL 側では、列は MySQL のネイティブな JSON 型ではなく、CHECK 制約付きの LONGTEXT になります。JSON_EXTRACT() と JSON_LENGTH() で読み戻すと、元のデータと同一の結果が得られるため、何も失われません。しかし、列の宣言された型は、新規の MySQL スキーマが使うものとは異なります。移行先でネイティブな JSON 型が必要なら、ロード後に列を変更します。
これは、元の CHECK (json_valid(...)) 制約を列に付けたまま残します。ダンプはその制約に名前を付けていないため、CREATE TABLE の実行時にサーバーが products_chk_1 のような名前を付けました。ALTER の前からすでに存在しています。MySQL は型レベルですでに無効な JSON を拒否するため、ネイティブな JSON 列では無害ですが、LONGTEXT の定義から残った不要な制約です。クリーンなスキーマにしたい場合は削除します。

認証の違い

MariaDB と MySQL のクライアントは同じワイヤプロトコルを話し、一方から他方へのプレーンなパスワード認証による接続は動作します。引き継がれないのは、アカウントの定義そのものです。mysqldump はデフォルトでは mysql.user テーブルをダンプしないため、アカウントと権限は移行先で手作業で再作成する必要があり、そのための構文は異なります。 パスワード付きで作成された MariaDB のアカウントは、次のように表示されます。
デフォルトの caching_sha2_password プラグインを使う MySQL または VillageSQL では、同じステートメントは代わりに次のように表示されます。
MariaDB の SHOW CREATE USER ステートメントを MySQL にコピーしないでください。移行先で CREATE USER ... IDENTIFIED BY '<password>' によってアカウントを新規に作成し、サーバー自身のデフォルトプラグインを選ばせてから、GRANT ステートメントを再発行します。 セットアップしたばかりの MariaDB インストール(たとえば新規の Homebrew インストール)に対して移行をテストしていて、パスワードが正しいのに、パスワード付きの名前付きアカウントが「Access denied」で拒否される場合は、まず匿名アカウントを確認します。
セキュリティ設定を行っていない MariaDB インストールでは、''@'localhost' と ''@'<hostname>' が残っていることがあります。ホストの一致はユーザー名の一致より優先されるため、localhost に解決される接続は、名前付きアカウントより先に匿名アカウントに一致し、匿名アカウントはパスワードを期待しないため拒否されます。これは MariaDB 側のインストールの問題で、データとともに MySQL に引き継がれるものではありませんが、匿名アカウントを削除するまでは、移行元でのテストを混乱させることがあります。

移行の進め方

  1. スキーマとデータをダンプします。 mysqldump を使います(MariaDB ホストでは通常 MariaDB 独自の mariadb-dump へのシンボリックリンクです。mysqldump --version を実行してどちらかを確認します)。
  2. ロードを試みる前に、ダンプから CREATE SEQUENCE、INET6、および RETURNING を検索します。 この 3 つはいずれも、ロードがすでに途中まで進むまで有用なエラーを出しません。
  3. まずスクラッチ用のデータベースにロードを試みます。 CREATE SEQUENCE または INET6 の失敗は、そのステートメントでスクリプト全体を中止します。そのため、ファイル内で先に定義されたテーブルはすでにロードされ、後に定義されたテーブルはロードされていません。半分ロードされたデータベースにパッチを当てるのではなく、ダンプを修正して新規のデータベースに再ロードします。
  4. 移行元のスキーマが名前のない外部キーに頼っていた場合は、外部キー制約名の衝突を確認します。 grep -o 'CONSTRAINT \[0-9]*`’ dump.sql` で見つかります。
  5. アカウントと権限を手作業で再作成します。 mysqldump にはそれらが含まれず、CREATE USER / SHOW CREATE USER の構文は 2 つのサーバーで異なります。
  6. 行数を検証し、JSON 列を抜き取り検査します。 JSON 列は黙って LONGTEXT としてロードされます。ネイティブな JSON 列に変換するかどうかを決める前に、JSON_EXTRACT() でデータが往復することを確認します。

よくある質問

同じバージョン系統の MySQL を移行先とする場合、MariaDB の mysqldump ファイルに編集は必要ですか?

スキーマがシーケンス、INET6、RETURNING、または名前のない外部キーを使っていなければ、同じダンプは多くの場合、変更なしでロードされます。スキーマが「ただのテーブルとデータ」だから成功するだろうと仮定するのではなく、まずスクラッチ用のデータベースに対してロードをテストしてください。

ネイティブな MySQL の JSON 列は、MariaDB のダンプを通して正しく往復しますか?

値は正しく往復します。列の型は往復しません。MariaDB は JSON 列を CHECK 制約付きの LONGTEXT としてダンプし、それがそのまま MySQL にロードされます。後で明示的に ALTER TABLE ... MODIFY で列を JSON にしない限り、そのままです。

MySQL クライアントで MariaDB サーバーに、またはその逆に接続できますか?

はい、通常のパスワード認証による接続であれば可能です。どちらも同じワイヤプロトコルを使い、一方のライブラリでビルドされたクライアントは、パスワード付きのアカウントが存在しさえすれば、他方のサーバーのアカウントに対して認証できます。両者が分かれるのは、接続ではなく、各サーバーが受け入れる SQL です。

トラブルシューティング

関連項目