MySQL 8.0 で外部ディスクのディレクトリにテーブルファイルを配置する

MySQL 8.0
この記事は最終更新から2年以上経過しています。内容が古くなっている可能性があります。

MySQL のテーブルデータ格納領域と言えば、datadir パラメータに指定したディレクトリ、というのが一般的によく知られた認識だと思います。

datadir には単一のディレクトリパスのみ指定可能です。

では、以下のような運用上や性能面の理由でデータベーススキーマごとだったりテーブルごとだったりで別ディスクにデータを分散配置したいという場合はどうすればいいでしょうか。

  • 特定のテーブルに集中するディスクI/Oの負荷を分散したい
  • 特定のデータベーススキーマのデータサイズが増大してきたので、現在よりも大きな容量の別ディスク側に移動させたい
  • 上記のような事態を未然に予防するため、初期構築時点でディスク構成を設計しておきたい

他の RDBMS でも一般的な手法だと思いますが、あまり MySQL ではメジャーではないように思います(個人的な見解ですが…)

そこで、今回 MySQL 8.0 (8.0.21~) における設定方法を紹介したいと思います。

目次

主な3つの方法について

異なるデータをそれぞれ別のディスクに分けて格納する方法として、リファレンスマニュアルには3つの方法が公開されています。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 15.6.1.2 外部でのテーブルの作成

1. CREATE TABLE ステートメントで DATA DIRECTORY 句を指定する

以下のコマンドで外部ディレクトリへのパスを指定してテーブルを作成します。

2. CREATE TABLE ... TABLESPACE を使用する

1 のコマンドに TABLESPACE = innodb_file_per_table が含まれるかたちです。

innodb_file_per_table = ON でない場合でも作成することができるということ以外は、1 の方法で作成した場合と機能上変わりはありません。

MySQL 8.0 においてはデフォルトで innodb_file_per_table = ON(file-per-tableモードが有効) ですので、基本的にこのコマンドを使うことは余りないのではと考えます。

3. 外部一般テーブルスペースにテーブルを作成する

一般テーブルスペースを外部ディレクトリに作成するという方法です。

そのあと、作成した一般テーブルスペース内にテーブルを作成します。

一般テーブルスペースでデータ管理したことのない場合は、通常の file-per-tableモードとは領域管理の仕様や制限が異なるので、理解した上でこの方法を選択してください。

テーブルスペースの一般的な制限事項については、以下のリファレンスマニュアルページをご確認ください。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 15.6.3.3 一般テーブルスペース

CREATE TABLE … DATA DIRECTORY でテーブルを作成してみる

それでは、具体的な設定であったり作成の手順を確認してみたいと思います。

前述の3つの方法のうち、今回は、最も選択されるであろう 1 の CREATE TABLE ... DATA DIRECTORY コマンドを使った構成を試してみます。

今回使用したバージョンは MySQL 8.0.30 です。

まず、データディレクトリ外のディレクトリを準備します。

別ディスクを用いる場合は、ファイルシステムとしてマウントして、ディレクトリ作成を済ませてください。

※Linuxでしたら LVMで構成しておくと今後柔軟に領域管理できてよいと思います。

このときのポイントとしては、対象ディレクトリに MySQL起動ユーザ(mysql)の書き込み権限を与えておく必要があります。

そして my.cnf の [mysqld] セクションに以下のように対象ディレクトリの絶対パスを設定します。

起動時に InnoDB にディレクトリを認識させるには、datadir, innodb_data_home_dir, innodb_undo_directory, innodb_directories パラメータで指定します。
(指定されたディレクトリは、起動時にテーブルスペースファイルがスキャンされる対象となります)

今回の用途としては、データディレクトリ外のテーブルスペースファイル格納ディレクトリを指定するために innodb_directories を設定します。

このパラメータの設定が無い場合、CREAT TABLE ... DATA DIRECTORYCREATE TABLESPACE ... ADD DATAFILE を実行しようとすると以下のエラーで失敗してしまいます。

ERROR 3121 (HY000): The DATA DIRECTORY location must be in a known directory.

innodb_file_per_table は前述の通り、デフォルトの ON のままとしておきます。

db1 スキーマに属するテーブル tbl1 を作成してみます。

コマンドでの作成後に、OS 上の実際のディレクトリとファイルを確認してみます。

innodb-directories パラメータで指定したディレクトリ内に、スキーマ名のディレクトリが作成され、その配下にテーブルスペースファイル(.ibd)が作成されました。

file-per-tableモードなので、CREATE DATABASE を実行したときには datadir(今回はデフォルトの/var/lib/mysql)配下にスキーマ名のディレクトリは作成されましたが、そちらにはテーブルは作成されていないことが確認できます。

INFORMATION_SCHEMA.FILES からも情報を確認することができます。

既存のテーブルスペースファイルを別ディスクのディレクトリに移動する

状況や目的によっては既存テーブルを別ディスクに移動したい場合もあるかと思います。

残念ながらオンラインで別ディレクトリにテーブル移動する(格納先を変更する)ことはできません。

以下のように ALTER TABLE ... DATA DIRECTORY と実行しても DATA DIRECTORY は無視されてしまうのです。

このことはリファレンスマニュアルにも明記されています。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.1.9 ALTER TABLE ステートメント

すべてのテーブルオプションの詳細は、セクション13.1.20「CREATE TABLE ステートメント」 を参照してください。 ただし、テーブルオプションとして指定されている場合、ALTER TABLE は DATA DIRECTORY および INDEX DIRECTORY を無視します。

よって、以下のマニュアルにある通り、MySQL インスタンスを停止してからテーブルスペースファイルを移動させる必要があります。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 15.6.3.6 サーバーがオフラインのときのテーブルスペースファイルの移動

ここに記載されている手順に沿って実施してみます。

DATA DIRECTORY 句無しの通常の CREATE TABLE コマンドで作成されたテーブルが移動対象です。

MySQL を停止し、外部ディレクトリへスキーマ名ディレクトリごと移動します。

※外部ディレクトリ側にスキーマ名ディレクトリがすでに存在する場合は、任意のテーブルスペースファイルのみ(テーブル単位で)移動することでも可能です。

innodb-directories に指定したディレクトリ以外の場所に移動させたい場合は、innodb-directories パラメータにそのパスを追加してください。(複数のパスが指定可能)

MySQL を起動します。

無事移動が成功していることが確認できます。

SHOW CREATE TABLE コマンドの結果は、CREATE TABLE 実行時の定義が参照されるため、移動前と変化はありません。(DATA DIRECTORY= は付与されません)

CREATE TABLE ... DATA DIRECTORY コマンドで作成したテーブルは格納先ディレクトリの情報が SHOW CREATE TABLE では表示されるので、この点はご注意ください。

レプリケーション構成での注意点

基本的にはソース・レプリカでディレクトリ構成は合わせるようにすることが大事です。

例えば、ソース・レプリカともに innodb-directories を指定してはいるものの、レプリカ側に対象ディレクトリが存在し無い(例えば作成漏れなど)、という状態で CREATE TABLE ... DATA DIRECTORY コマンドを実行すると下記のエラーでレプリケーション停止してしまいます。

この場合、改めてレプリカ側に対象ディレクトリを作成すれば、レプリケーションを再開して同期適用が成功します。

バックアップ・リストアでの注意点や確認事項

別ディスクに格納先が変更された影響で、バックアップやリストアが出来なくなる事態は避けたいところです。

コールドバックアップ時

datadir の場合もそうですが、外部ディスクストレージを使用する都合上、コールドバックアップ時のケアが必要です。

リファレンスマニュアルから引用します。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 15.6.1.2 外部でのテーブルの作成

  • MySQL では、最初にテーブルスペースデータファイルが開いた状態で保持されるため、デバイスをディスマウントできませんが、サーバーがビジー状態の場合は最終的にファイルが閉じられる可能性があります。 MySQL の実行中に外部デバイスを誤ってディスマウントしたり、デバイスの切断中に MySQL を起動したりしないように注意してください。 関連付けられたデータファイルがないときにテーブルにアクセスしようとすると、重大なエラーが発生し、サーバーの再起動が必要になります。
  • 必要なパスにデータファイルが見つからない場合、サーバーの再起動が失敗することがあります。 この場合、テーブルスペースデータファイルをバックアップからリストアするか、テーブルを削除して data dictionary から削除できます。
  • NFS マウントされたボリュームにテーブルを配置する前に、MySQL での NFS の使用 で概説されている潜在的な問題を確認します。
  • LVM スナップショット、ファイルコピーまたはその他のファイルベースのメカニズムを使用してテーブルデータファイルをバックアップする場合は、バックアップが発生する前に、必ず FLUSH TABLES … FOR EXPORT ステートメントを使用して、メモリーにバッファリングされるすべての変更が flushed からディスクになるようにします。

mysqldump, mysql shell, mydumper

CREATE TABLE ... DATA DIRECTORY コマンドを使って新規で作ったテーブルをダンプする分には特に支障なく利用できます。

ただし、[既存のテーブルスペースファイルを別ディスクのディレクトリに移動する] のところでお伝えしたのと同様の問題は、ダンプ時にテーブル定義を SHOW CREATE TABLE 相当で取得するバックアップツールにおいて生じます。

つまり、ダンプファイルに出力された、別ディスクのディレクトリにテーブルスペースファイルを移動した既存テーブルの CREATE TABLE には DATA DIRECTORY 句が付与されません。

そのため、ダンプファイルを単純にリストアしてしまうと、移動前の datadir 配下にテーブルが作成されてしまいます。

今回確認した限りでは、以下のバックアップツールで発生することが判明しています。

  • mysqldump 8.0.30
  • MySQL Shell 8.0.30 util.dumpInstance()
  • mydumper 0.12.6-1

リストア前に、移動したテーブルについてはダンプファイル内の該当箇所に DATA DIRECTORY 句を追記する対応が必要となります。

リストア時にエラーにならないため、意図しない場所にテーブルスペースファイルが作成されてしまったことに気付かない可能性が高いので、ご注意ください。

Percona XtraBackup

XtraBackup はどのような挙動になるでしょうか。

結論から言うと、外部テーブルスペースにも対応しているので、バックアップ・リストア共に問題なく動作します。

XtraBackup のリリースバージョンの都合により、以下は MySQL 8.0.28 + XtraBackup 8.0.29 で確認しています。

バックアップ時

外部ディレクトリがスキャンされている様子が伺えます。

バックアップ出力先ディレクトリにテーブルスペースファイルが集約してコピーされています。

XtraBackup では外部ディレクトリに配置されたテーブルスペースをどのように判別しているのか、調べてみました。

バックアップ後、バックアップ出力ディレクトリ内に xtrabackup_tablespaces というファイルが生成されていました。
このファイル内に、JSON形式で対象リストと思しき情報が記録されていました。

ソースコードを確認すると、以下リンク先の関数内で INFORMATION_SCHEMA からクエリしてリストを作成していました。

https://github.com/percona/percona-xtrabackup/blob/749fafd4a55ffa6e53de325a63aa6b550e597651/storage/innobase/xtrabackup/src/space_map.cc#L67

リストア時

上述の対象テーブルスペースのリストファイルを元に、適切な対象ディレクトリへバックアップファイルがコピーされているのが確認できます。

MySQL Enterprise Backup

Enterprise Edition で利用可能な MySQL Enterprise Backup (8.0.30) でも試してみました。

こちらもバックアップ・リストアともに正常に外部ディレクトリのテーブルスペースファイルを対象として動作することが確認できます。

バックアップ

リストア

もしその他のバックアップツールを利用中の場合は、念の為動作確認を行っていただくことを推奨します。

まとめ

データディレクトリ外にデータベースやテーブルを配置するには、以前のバージョン(5.6 や 5.7) まではというと、シンボリックリンクを用いた方法がありました。

MySQL :: MySQL 5.7 Reference Manual :: 8.12.3 Using Symbolic Links

ただし、この方法は InnoDB のテーブルでは諸々問題が生じることからサポートされておらず、その正規の代替手段が今回紹介した方法であるという経緯があります。

現在運用中にデータ格納先に関して、記事冒頭で挙げたような問題を抱えている場合はもちろんのこと、MySQL 8.0 にアップグレードする際にも、今回のテーブル作成方法の採用を検討してみてはいかがでしょうか。

スマートスタイルTECHブログについて

スマートスタイルTECHブログでは、日頃MySQLのサポート業務に従事している有資格者で構成された技術サポートチームがMySQLに関する技術情報を発信しています。データベースのお困りごとはお気軽にご相談下さい。

よかったらシェアしてね!
  • URLをコピーしました!
目次