この記事は Fredric DescampsのMigrate MyISAM tables from MySQL 5.7 to 8.0を日本語版として翻訳および再編集したものです。
MySQLは、以前からデフォルトのトランザクションエンジンとしてInnoDBを採用しています。もしまだMyISAMを使用している場合は、InnoDBに変換してそのベネフィットを感じていただきたいと思います。
MySQL 8.0にアップグレードする予定なら、MyISAMテーブルを処理するためのオプションがあります。
MyISAMテーブルの使用は推奨されないことに注意してください。MyISAMはACIDに準拠していないため、データの損失につながる可能性があります。
また、MyISAMは完全なテーブルロックのみをサポートし、行レベルのロック機能はありません。
5.7では、MyISAMはMYD、MYI、FRMファイルを保持していました。8.0では、FRMはSDI(Serialized Dictionnary Information)に置き換わっています。
MyISAMテーブルを8.0に移行するための方法について説明します。
移行方法
MyISAMデータを8.0に移行するには、複数の方法があります。
- インプレースアップグレード(mysqldを停止し、バイナリを置き換えてmysqldを再起動する)
- 論理的なダンプとロード(MySQL Shellを使用するのが便利です)
- 物理的なコピー(若干の手間がかかります)
方法2、3は、MySQL5.7と8.0が別サーバーにインストールされている場合に有効です。
移行後はInnoDBエンジンに変更することをお勧めします!
インプレースアップグレード
5.7から8.0への移行は、これが最も一般的な方法です。こちらのブログ記事を参考にしてください。
論理的なダンプとロード
MySQL 5.7 の MyISAM データソースと MySQL 8.0 の移行先が異なるサーバにある場合、データの論理的ダンプ&ロードは、一方のサーバからもう一方のサーバに移行するために良い方法です。
このようなダンプとロードを実行するには、MySQLシェルユーティリティが一番適切なツールです。
ここでは、MySQLシェルユーティリティに関連した記事を紹介します。
- MySQL Shell Dump & Load and Compression
- How to copy a Schema using MySQL Shell Dump & Load Utility?
- MySQL Shell 8.0.24 Dump now supports array arguments in non-interactive mode
- Migrate Ownership of your stored routines, views and triggers for MySQL in 2021
- Migrate from on premise MySQL to MySQL Database Service
推奨されているInnoDBに移行する場合、データのロードは3ステップで行うことができます。
- テーブルの定義をロードする
- この空のテーブルのエンジンをInnoDBに変更する
- データをロードする
では、実際に見てみましょう。まずはダンプ取得から行います。
No default schema selected; type \use <schema> to set one.
MySQL 127.0.0.1:5731 2021-08-02 12:10:15
JS > util.dumpSchemas(['my_isam_db'],'/tmp/dump')
Acquiring global read lock
Global read lock acquired
Gathering information – done
All transactions have been started
Locking instance for backup
NOTE: Backup lock is not supported in MySQL 5.7 and DDL changes will not be blocked.
The dump may fail with an error or not be completely consistent
if schema changes are made while dumping.
Global read lock has been released
Writing global DDL files
Preparing data dump for table `my_isam_db`.`t1`
Data dump for table `my_isam_db`.`t1` will be chunked using column `id`
Writing DDL for schema `my_isam_db`
Data dump for table `my_isam_db`.`t1` will be written to 1 file
1 thds dumping – 100% (2 rows / ~2 rows), 0.00 rows/s, 0.00 B/s uncompressed, 0.00 B/s compressed
Duration: 00:00:00s
Schemas dumped: 1
Tables dumped: 1
Uncompressed data size: 55 bytes
Compressed data size: 51 bytes
Compression ratio: 1.1
Rows written: 2
Bytes written: 51 bytes
Average uncompressed throughput: 55.00 B/s
Average compressed throughput: 51.00 B/s
複数のスキーマ、またはインスタンス全体をダンプすることができます。
ここで、MySQL Shell を MySQL 8.0 に接続し、テーブル定義のみをロードしてみます。
Loading DDL only from '/tmp/dump' using 4 threads.
Opening dump…
Target is MySQL 8.0.26. Dump was produced from MySQL 5.7.31
WARNING: Destination MySQL version is newer than the one where the dump was created.
Loading dumps from different major MySQL versions is not fully supported and may not work.
The 'ignoreVersion' option is enabled, so loading anyway.
Checking for pre-existing objects…
Executing common preamble SQL
Executing DDL script for schema `my_isam_db`
[Worker002] Executing DDL script for `my_isam_db`.`t1`
Executing common postamble SQL
No data loaded.
0 warnings were reported during the load.
loadData:falseを使用していることがおわかりいただけると思います。
ここで、エンジンをInnoDBに変更します。
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.0005 sec)
Query OK, 0 rows affected (0.3546 sec)
Records: 0 Duplicates: 0 Warnings: 0
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET latin1 DEFAULT NULL,
`inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.0012 sec)
また、このタイミングでキャラクタセットをUFT8MB4に変更したこともお分かりいただけると思います。
ここまででデータをロードする準備ができました。
Loading Data only from '/tmp/dump' using 4 threads.
Opening dump…
Target is MySQL 8.0.26. Dump was produced from MySQL 5.7.31
WARNING: Destination MySQL version is newer than the one where the dump was created.
Loading dumps from different major MySQL versions is not fully supported and may not work.
The 'ignoreVersion' option is enabled, so loading anyway.
NOTE: Load progress file detected. Load will be resumed from where it was left, assuming no external updates were made.
You may enable the 'resetProgress' option to discard progress for this MySQL instance and force it to be completely reloaded.
Executing common preamble SQL
[Worker000] my_isam_db@t1@@0.tsv.zst: Records: 2 Deleted: 0 Skipped: 0 Warnings: 0
Executing common postamble SQL
1 chunks (2 rows, 55 bytes) for 1 tables in 1 schemas were loaded in 1 sec (avg throughput 55.00 B/s)
0 warnings were reported during the load.
完了しました!
物理的なコピー
データファイル(.MYDと.MYI)を元のサーバーから移行先のサーバーにコピーしたい方もいらっしゃると思います。
ただし、SDIが欠落しテーブルが認識されないため、実行することができません。スキーマを作成するまでは、データベースとテーブルが無視されるだけで、エラーは発生しません。
ERROR 3678 (HY000): Schema directory './my_isam_db' already exists.
This must be resolved manually (e.g. by moving the schema directory to another location).
では、どのような方法があるのでしょうか?
最も安全な方法は、テーブル定義のみのダンプを作成することです。(前のセクションと同じダンプファイルを使用することもできますが、非常に大きなデータをダンプすることを避けるためにファイルコピーを選択するのかもしれません)
では、テーブル定義だけを含むダンプを取得してみましょう。
Acquiring global read lock
Global read lock acquired
Gathering information – done
All transactions have been started
Locking instance for backup
NOTE: Backup lock is not supported in MySQL 5.7 and DDL changes will not be blocked.
The dump may fail with an error or not be completely consistent if schema changes are made while dumping.
Global read lock has been released
Writing global DDL files
Running data dump using 4 threads.
NOTE: Progress information uses estimated values and may not be accurate.
Writing DDL for table `my_isam_db`.`t1`
Writing DDL for schema `my_isam_db`
0% (0 rows / ~2 rows), 0.00 rows/s, 0.00 B/s uncompressed, 0.00 B/s compressed
Duration: 00:00:00s
Schemas dumped: 1
Tables dumped: 1
Uncompressed data size: 0 bytes
Compressed data size: 0 bytes
Compression ratio: 0.0
Rows written: 0
Bytes written: 0 bytes
Average uncompressed throughput: 0.00 B/s
Average compressed throughput: 0.00 B/s
これで、取得したダンプをロードすることができます。ロードすると、.FRMファイルはなく、.SDIが存在する空のMyISAMテーブルが作成されます。
Loading DDL and Data from '/tmp/dump_ddl' using 4 threads.
Opening dump…
Target is MySQL 8.0.26. Dump was produced from MySQL 5.7.31
WARNING: Destination MySQL version is newer than the one where the dump was created.
Loading dumps from different major MySQL versions is not fully supported and may not work. The 'ignoreVersion' option is enabled, so loading anyway.
Checking for pre-existing objects…
Executing common preamble SQL
Executing DDL script for schema `my_isam_db`
[Worker000] Executing DDL script for `my_isam_db`.`t1`
Executing common postamble SQL
No data loaded.
0 warnings were reported during the load.
SQLコマンドでテーブルが作成されたことが確認できます。
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
1 row in set (0.0003 sec)
ファイルシステムでも確認することができます。
-rw-r—– 1 mysql mysql 3.6K Aug 2 12:49 t1_5017.sdi
-rw-r—– 1 mysql mysql 0 Aug 2 12:49 t1.MYD
-rw-r—– 1 mysql mysql 1.0K Aug 2 12:49 t1.MYI
あとは、MYDとMYIのファイルを正しい場所にコピーするだけです。ただし、その前にMySQLを停止する必要があります。
[root@imac mysql]# cp data/my_isam_db/t1.M* /var/lib/mysql/my_isam_db/
cp: overwrite '/var/lib/mysql/my_isam_db/t1.MYD'? y
cp: overwrite '/var/lib/mysql/my_isam_db/t1.MYI'? y
ファイルのコピー後にMySQLを再起動します。
追記
時にはMySQLサーバはもう運用されていないが、データはどこか(バックアップやディスクなど)にあるということがあります。
スキーマとテーブル定義のダンプを実行できない場合、FRMファイルがあれば、テーブル定義を提供する外部ツール:dbsakeが利用できる可能性があります。
dbsakeは、frmファイルを読むことができるだけでなく、fincoreの機能に関しても特に興味深いツールです。
では、これらのファイルがある古いMySQL 5.7ディレクトリにしかアクセスできないと仮定してみましょう。
total 24K
-rw-r—– 1 fred fred 65 Jul 29 08:45 db.opt
-rw-r—– 1 fred fred 8.5K Jul 29 09:29 t1.frm
-rw-r—– 1 fred fred 40 Jul 29 09:29 t1.MYD
-rw-r—– 1 fred fred 2.0K Jul 29 09:29 t1.MYI
そのfrmファイルを使ってdbsakeを使えば、テーブルの定義を取得することができます。
—
— Table structure for table `t1`
— Created with MySQL Version 5.7.31
—
CREATE TABLE `t1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
上記はMySQL 8.0に移行する必要があるすべてのMyISAMテーブルに対して行うことができます。
結論
このように、古いバージョンのMySQLから8.0にMyISAMデータを移行することは可能です。
しかし、最も重要なことはより高性能で安全なエンジンであるInnoDBに変更することです!
