第 14 章 InnoDB ストレージエンジン

目次

14.1 InnoDB 入門
14.1.1 デフォルトの MySQL ストレージエンジンとしての InnoDB
14.1.2 InnoDB の可用性チェック
14.1.3 InnoDB の無効化
14.2 InnoDB の概念とアーキテクチャー
14.2.1 MySQL および ACID モデル
14.2.2 InnoDB のトランザクションモデルおよびロック
14.2.3 InnoDB のロックモード
14.2.4 一貫性非ロック読み取り
14.2.5 ロック読み取り (SELECT ... FOR UPDATE および SELECT ... LOCK IN SHARE MODE)
14.2.6 InnoDB のレコード、ギャップ、およびネクストキーロック
14.2.7 ネクストキーロックによるファントム問題の回避
14.2.8 InnoDB のさまざまな SQL ステートメントで設定されたロック
14.2.9 暗黙的なトランザクションコミットとロールバック
14.2.10 デッドロックの検出とロールバック
14.2.11 デッドロックの対処方法
14.2.12 InnoDB マルチバージョン
14.2.13 InnoDB テーブルおよびインデックスの構造
14.3 InnoDB の構成
14.3.1 読み取り専用操作用の InnoDB の構成
14.4 InnoDB の管理
14.5 InnoDB テーブルスペース管理
14.5.1 InnoDB テーブルスペースの作成
14.5.2 InnoDB File-Per-Table モード
14.5.3 File-Per-Table モードの有効化および無効化
14.5.4 テーブルスペースの位置の指定
14.5.5 テーブルスペースの別のサーバーへのコピー (トランスポータブルテーブルスペース)
14.5.6 個別のテーブルスペースへの InnoDB Undo ログの格納
14.5.7 InnoDB ログファイルの数またはサイズの変更、および InnoDB テーブルスペースのサイズの変更
14.5.8 共有テーブルスペースでの RAW ディスクパーティションの使用
14.6 InnoDB テーブルの管理
14.6.1 InnoDB テーブルの作成
14.6.2 別のマシンへの InnoDB テーブルの移動またはコピー
14.6.3 トランザクションを使用した DML 操作のグループ化
14.6.4 MyISAM から InnoDB へのテーブルの変換
14.6.5 InnoDB での AUTO_INCREMENT 処理
14.6.6 InnoDB と FOREIGN KEY 制約
14.6.7 InnoDB テーブル上の制限
14.7 InnoDB 圧縮テーブル
14.7.1 テーブル圧縮の概要
14.7.2 テーブル圧縮の有効化
14.7.3 InnoDB テーブルの圧縮の調整
14.7.4 実行時の圧縮のモニタリング
14.7.5 InnoDB テーブルでの圧縮の動作
14.7.6 OLTP ワークロードの圧縮
14.7.7 SQL 圧縮構文の警告とエラー
14.8 InnoDB のファイル形式管理
14.8.1 ファイル形式の有効化
14.8.2 ファイル形式の互換性の確認
14.8.3 使用されているファイル形式の識別
14.8.4 ファイル形式のダウングレード
14.8.5 将来の InnoDB ファイル形式
14.9 InnoDB の行ストレージと行フォーマット
14.9.1 InnoDB 行ストレージの概要
14.9.2 テーブルの行フォーマットの指定
14.9.3 DYNAMIC および COMPRESSED 行フォーマット
14.9.4 COMPACT および REDUNDANT 行フォーマット
14.10 InnoDB のディスク I/O とファイル領域管理
14.10.1 InnoDB ディスク I/O
14.10.2 ファイル領域管理
14.10.3 InnoDB チェックポイント
14.10.4 テーブルのデフラグ
14.10.5 TRUNCATE TABLE によるディスク領域の再利用
14.11 InnoDB とオンライン DDL
14.11.1 オンライン DDL の概要
14.11.2 オンライン DDL でのパフォーマンスと並列性に関する考慮事項
14.11.3 オンライン DDL の SQL 構文
14.11.4 DDL ステートメントの結合または分離
14.11.5 オンライン DDL の例
14.11.6 オンライン DDL の実装の詳細
14.11.7 オンライン DDL でのクラッシュリカバリの動作のしくみ
14.11.8 パーティション化された InnoDB テーブルに対するオンライン DDL
14.11.9 オンライン DDL の制限
14.12 InnoDB の起動オプションおよびシステム変数
14.13 InnoDB のパフォーマンス
14.13.1 InnoDB バッファープールの構成
14.13.2 InnoDB 相互排他ロックおよび読み取り/書き込みロックの実装
14.13.3 InnoDB のためのメモリーアロケータの構成
14.13.4 InnoDB 変更バッファリングの構成
14.13.5 InnoDB のスレッド並列性の構成
14.13.6 InnoDB バックグラウンド I/O スレッドの数の構成
14.13.7 グループコミット
14.13.8 InnoDB マスタースレッドの I/O レートの構成
14.13.9 InnoDB スピンループでの PAUSE 命令の使用
14.13.10 スピンロックのポーリングの構成
14.13.11 InnoDB の MySQL パフォーマンススキーマとの統合
14.13.12 複数のロールバックセグメントによるスケーラビリティーの向上
14.13.13 InnoDB のパージスケジューリングの構成
14.13.14 InnoDB の読み取り専用トランザクションの最適化
14.13.15 チェックサムの高速化のための CRC32 チェックサムアルゴリズムの使用
14.13.16 オプティマイザ統計
14.13.17 InnoDB テーブルに対する ANALYZE TABLE の複雑さの推定
14.14 InnoDB INFORMATION_SCHEMA テーブル
14.14.1 圧縮に関する InnoDB INFORMATION_SCHEMA テーブル
14.14.2 InnoDB INFORMATION_SCHEMA トランザクションおよびロックテーブル
14.14.3 InnoDB INFORMATION_SCHEMA システムテーブル
14.14.4 InnoDB INFORMATION_SCHEMA FULLTEXT インデックステーブル
14.14.5 InnoDB INFORMATION_SCHEMA バッファープールテーブル
14.14.6 InnoDB INFORMATION_SCHEMA メトリックテーブル
14.15 InnoDB モニター
14.15.1 InnoDB モニターのタイプ
14.15.2 InnoDB モニターの有効化
14.15.3 InnoDB 標準モニターおよびロックモニターの出力
14.15.4 InnoDB テーブルスペースモニターの出力
14.15.5 InnoDB テーブルモニターの出力
14.16 InnoDB のバックアップとリカバリ
14.16.1 InnoDB のリカバリプロセス
14.17 InnoDB と MySQL レプリケーション
14.18 InnoDB と memcached の統合
14.18.1 InnoDB と memcached の組み合わせの利点
14.18.2 InnoDB および memcached の統合のアーキテクチャー
14.18.3 InnoDB Memcached プラグインの概要
14.18.4 InnoDB memcached プラグインのセキュリティーに関する考慮事項
14.18.5 InnoDB memcached インタフェース用のアプリケーションの作成
14.18.6 レプリケーションでの InnoDB memcached プラグインの使用
14.18.7 InnoDB memcached プラグインの内部構造
14.18.8 InnoDB memcached プラグインのトラブルシューティング
14.19 InnoDB のトラブルシューティング
14.19.1 InnoDB の I/O に関する問題のトラブルシューティング
14.19.2 InnoDB のリカバリの強制的な実行
14.19.3 InnoDB データディクショナリの操作のトラブルシューティング
14.19.4 InnoDB のエラー処理
14.19.5 InnoDB のエラーコード
14.19.6 オペレーティングシステムのエラーコード

14.1 InnoDB 入門

InnoDB は、高い信頼性と高いパフォーマンスとのバランスをとる汎用のストレージエンジンです。MySQL 5.5 の時点では、これがデフォルトの MySQL ストレージエンジンです。MySQL 5.6 では、ENGINE= 句を指定せずに CREATE TABLE ステートメントを発行すると、InnoDB テーブルが作成されます。

InnoDB の主要な利点

InnoDB テーブルの主要な利点は、次のとおりです。

  • その DML 操作は、トランザクションにユーザーデータを保護するためのコミットロールバック、およびクラッシュリカバリ機能が備わっている ACID モデルに従っています。

  • 行レベルのロックと Oracle スタイルの一貫性読み取りを使用すると、複数ユーザーの並列性およびパフォーマンスが向上します。

  • InnoDB テーブルでは、主キーに基づいてクエリーが最適化されるように、ディスク上のデータが整列されます。

  • データの整合性を保つために、InnoDB では FOREIGN KEY 制約もサポートされています。挿入、更新、および削除によってさまざまなテーブル間で不整合が発生しないかを確認するために、これらの操作がすべてチェックされます。

  • 同じステートメント内でも、InnoDB のテーブルと別の MySQL ストレージエンジンのテーブルを混在させることができます。たとえば、結合操作を使用すると、単一のクエリーで InnoDB テーブルと MEMORY テーブルのデータを結合できます。

  • InnoDB は、大きなデータボリュームを処理する際に、高い CPU の効率性と最大のパフォーマンスが実現されるように設計されています。

表 14.1 InnoDB ストレージエンジンの機能

機能Support
B ツリーインデックスはい
MVCCはい
T ツリーインデックスいいえ
インデックスキャッシュはい
クエリーキャッシュのサポートはい
クラスタデータベースのサポートいいえ
クラスタ化されたインデックスはい
ストレージの制限64T バイト
データキャッシュはい
データディクショナリ向け更新統計はい
トランザクションはい
ハッシュインデックスいいえ (InnoDB は、アダプティブハッシュインデックス機能に対して、内部的にハッシュインデックスを利用します。)
バックアップ/ポイントインタイムリカバリ (ストレージエンジン内ではなくサーバー内で実装されています。)はい
レプリケーションのサポート (ストレージエンジン内ではなくサーバー内で実装されています。)はい
ロック粒度
全文検索インデックスはい (InnoDB の FULLTEXT インデックスサポートは MySQL 5.6.4 以降で使用できます。)
圧縮データはい (圧縮された InnoDB テーブルは InnoDB Barracuda ファイルフォーマットを必要とします。)
地理空間インデックスのサポートはい (InnoDB の地理空間インデックスサポートは MySQL 5.7.5 以降で使用できます。)
地理空間データ型のサポートはい
外部キーのサポートはい
暗号化データ (ストレージエンジン内ではなくサーバー内で (暗号化関数を使って) 実装されています。)はい

InnoDB ストレージエンジンには、データとインデックスをメインメモリーにキャッシュするための独自のバッファープールが保持されています。デフォルトでは、innodb_file_per_table 設定が有効になっているため、新しい各 InnoDB テーブルとそれに関連付けられたインデックスが個別のファイルに格納されます。innodb_file_per_table オプションを無効にすると、InnoDB ではそのテーブルとインデックスがすべて単一のシステムテーブルスペースに格納されます。システムテーブルスペースは、複数のファイル (または生のディスクパーティション) で構成されている場合があります。InnoDB テーブルは、ファイルサイズが 2G バイトに制限されているオペレーティングシステム上でも、大量のデータを処理できます。

InnoDB の機能と MySQL で提供されているその他のストレージエンジンを比較する方法については、第15章「代替ストレージエンジン「ストレージエンジンの機能」表を参照してください。

InnoDB の拡張機能と新機能

MySQL 5.6 での InnoDB の拡張機能と新機能については、次を参照してください。

追加のリソース

  • InnoDB 関連の用語および定義については、MySQL 用語集を参照してください。

  • InnoDB ストレージエンジン専用のフォーラムには、MySQL Forums::InnoDB からアクセスできます。

  • InnoDB は、MySQL と同じ GNU GPL ライセンスバージョン 2 (1991 年 6 月) によって発行されています。MySQL ライセンスの詳細は、http://www.mysql.com/company/legal/licensing/を参照してください。

14.1.1 デフォルトの MySQL ストレージエンジンとしての InnoDB

MySQL は、使いやすく、高いパフォーマンスと拡張性を実現するという評価を勝ち得ています。MySQL 5.5 よりも前では、MyISAM がデフォルトのストレージエンジンでした。我々の経験上、ほとんどのユーザーはデフォルト設定を変更しませんでした。MySQL 5.5 以上では、InnoDB がデフォルトのストレージエンジンです。やはりほとんどのユーザーがデフォルト設定を変更しないと予想されます。ただし、InnoDB を使用すれば、デフォルト設定でもユーザーが RDBMS から期待する利点 (ACID トランザクション、参照整合性、およびクラッシュリカバリ) が得られます。InnoDB テーブルを使用して MySQL ユーザー、DBA、または開発者としての生活を改善する方法を探ってみましょう。

ストレージエンジンの使用傾向

MySQL の成長期の 1 年目には、初期の Web ベースのアプリケーションによって並列性と可用性の限界が押し広げられることはありませんでした。近年では、ハードドライブやメモリーの容量および価格性能比がすべて向上しています。MySQL のパフォーマンスの限界を押し広げているユーザーは、信頼性やクラッシュリカバリに多くの関心を持っています。MySQL データベースは、大規模で、高負荷で、強固で、分散型で、重要です。

InnoDB は、このようなユーザーの最優先事項に対処します。ストレージエンジンの使用傾向は、より拡張可能な InnoDB の方へシフトしています。したがって、MySQL 5.5 は、InnoDB をデフォルトのストレージエンジンにするための論理遷移リリースでした。

MySQL は、以前は MyISAM テーブルが必要だったユースケースへの対処に取り組み続けています。MySQL 5.6 以上には、次のような特性があります。

デフォルトの MySQL ストレージエンジンとしての InnoDB の重要性

MySQL 5.5.5 以降、新しいテーブル用のデフォルトのストレージエンジンは InnoDB です。この変更は、新たに作成されたテーブルの中で、ENGINE=MyISAM などの句を使用してストレージエンジンが指定されていないものに適用されます。このようにデフォルトの動作を変更すると、MySQL 5.5 は、MyISAM が使用されているテーブルが InnoDB に切り替えることによる利点を得られるかどうかを評価するための論理ポイントになる可能性があります。

MySQL 内部仕様の一部が実装されている mysql および information_schema データベースでは、引き続き MyISAM が使用されます。特に、付与テーブルを切り替えても、InnoDB を使用できません。

InnoDB テーブルの利点

MyISAM テーブルを使用しているが、技術的な理由でそれらに関与していない場合は、InnoDB テーブルを使用すると、さらに便利な点が数多く見つかるでしょう。

  • ハードウェアまたはソフトウェアの問題が原因でサーバーがクラッシュした場合でも、その時点でデータベースに何が発生していたのかには関係なく、データベースの再起動後に特別なことは何もする必要がありません。InnoDBクラッシュリカバリを使用すると自動的に、クラッシュ時の前にコミットされた変更はすべて完了し、処理中だったがコミットされなかった変更はすべて取り消されます。単に再起動し、終了した場所から続行するだけです。このプロセスは、MySQL 5.1 以前よりも大幅に高速になりました。

  • テーブルおよびインデックスのデータにアクセスすると、そのデータは InnoDBバッファープールにキャッシュされます。頻繁に使用されるデータは、直接メモリーから処理されます。このキャッシュは非常に数多くのタイプの情報に適用され、これにより処理速度が大幅に上がります。その結果、専用のデータベースサーバーでは、最大で物理メモリーの 80% が InnoDB のバッファープールに割り当てられます。

  • 関連データをさまざまなテーブルに分割すると、強制的に参照整合性が適用される外部キーを設定できます。データを更新または削除すると、ほかのテーブル内の関連データも自動的に更新または削除されます。プライマリテーブル内に対応するデータが存在しないセカンダリテーブルにデータを挿入しようとすると、自動的に不正なデータが除外されます。

  • ディスク上またはメモリー内のデータが破損した場合は、偽のデータを使用する前に、チェックサムメカニズムによって警告が発行されます。

  • テーブルごとに適切な主キーカラムを持つデータベースを設計すると、これらのカラムが関与する操作が自動的に最適化されます。WHERE 句、ORDER BY 句、GROUP BY 句、および結合操作では、主キーカラムへの参照が非常に高速です。

  • 挿入、更新、および削除は、変更バッファリングと呼ばれる自動化メカニズムによって最適化されます。InnoDB では、同じテーブルへの並列読み取りおよび書き込みアクセスが許可されているだけでなく、ディスク I/O が効率化されるように変更されたデータがキャッシュに入れられます。

  • パフォーマンスの利点は、長時間実行されるクエリーを含む巨大なテーブルだけに限定されません。同じ行が 1 つのテーブルから何度もアクセスされると、適応型ハッシュインデックスと呼ばれる機能に引き継がれ、ハッシュテーブルから読み取られたかのように、これらの検索がさらに高速になります。

InnoDB テーブルのベストプラクティス

長期間 InnoDB を使用していれば、すでにトランザクションや外部キーなどの機能について理解できています。そうでない場合は、この章全体でこれらについて参照してください。手短に言えば、次のとおりです。

  • もっとも頻繁にクエリーが実行されるカラム (複数の場合あり) を使用しているすべてのテーブルに、主キーを指定します。明示的な主キーが存在しない場合は、自動インクリメント値を指定します。

  • 複数のテーブルにある同じ ID 値に基づいて、それらのテーブルからデータを抽出する場合は、結合の概念を取り入れます。結合のパフォーマンスを高速にするには、結合カラム上に外部キーを定義し、各テーブル内でそれらのカラムを同じデータ型で宣言します。また、外部キーを使用すると、影響を受けるすべてのテーブルに削除または更新が反映され、親テーブルに対応する ID が存在しない場合は、子テーブル内のデータの挿入が回避されます。

  • 自動コミットをオフにします。1 秒間に何百回もコミットすると、パフォーマンスに上限が設定されます (これは、ストレージデバイスの書き込み速度で制限されます)。

  • 関連する DML 操作のセットを START TRANSACTIONCOMMIT ステートメントで囲むことで、トランザクションにグループ化します。頻繁にはコミットしたくない一方で、コミットなしで何時間も実行される INSERTUPDATE、または DELETE ステートメントの巨大なバッチも発生させたくありません。

  • LOCK TABLE ステートメントの使用を停止します。InnoDB は、一度に同じテーブルへのすべての読み取りおよび書き込みを行うことで、信頼性や高パフォーマンスを犠牲にせずに、複数のセッションを処理できます。行のセットへの排他的な書き込みアクセス権を取得するには、SELECT ... FOR UPDATE という構文を使用して、更新対象の行のみをロックします。

  • innodb_file_per_table オプションを有効にして、単一の巨大なシステムテーブルスペース内の代わりに、個別のファイルに各テーブル用のデータおよびインデックスを配置します。この設定は、テーブルの圧縮および高速の切り捨てなどのその他の機能の一部を使用する際に必要となります。

  • 使用中のデータおよびアクセスパターンによって、CREATE TABLE ステートメントで新しい InnoDB テーブルの圧縮機能 (ROW_FORMAT=COMPRESSED) からの利点が得られるかどうかを評価します。読み取りおよび書き込みの機能を犠牲にせずに、InnoDB テーブルを圧縮できます。

  • オプション --sql_mode=NO_ENGINE_SUBSTITUTION を付けてサーバーを実行して、CREATE TABLEENGINE= 句で指定されたストレージエンジンで問題が発生した場合に、別のストレージエンジンを使用してテーブルが作成されないようにします。

InnoDB テーブルに対する最近の改善点

  • テーブルおよび関連付けられたインデックスを圧縮できます。

  • 以前よりも大幅に小さいパフォーマンスや可用性への影響度で、インデックスを作成および削除できます。

  • テーブルの切り捨てが大幅に高速になり、InnoDB でのみ再使用される可能性のあるシステムテーブルスペース内の領域を解放するのではなく、オペレーティングシステムで再使用されるディスク領域を解放できます。

  • DYNAMIC 行フォーマットを使用することで、テーブルデータのストレージレイアウトが BLOB および長いテキストフィールドでより効率的になりました。

  • INFORMATION_SCHEMA テーブルでクエリーを実行することで、ストレージエンジンの内部動作をモニターできます。

  • performance_schema テーブルでクエリーを実行することで、ストレージエンジンのパフォーマンスを詳細にモニターできます。

  • パフォーマンスに関して多くの改善点があります。特に、クラッシュリカバリ、つまりデータベースが再起動するときにすべてのデータを自動的に整合させる処理の速度および信頼性が向上しました (InnoDB ユーザーが従来経験してきた速度よりずっと高速です)。データベースが大きいほど、大幅に速度が向上します。

    ほとんどの新しいパフォーマンス機能は自動的です。そうでない場合でも、必要なことは、多くても構成オプションの値を設定するだけです。詳細は、セクション14.13「InnoDB のパフォーマンス」を参照してください。アプリケーションコードで適用できる InnoDB 固有のチューニング技術については、セクション8.5「InnoDB テーブルの最適化」を参照してください。上級ユーザーは、セクション14.12「InnoDB の起動オプションおよびシステム変数」を再確認してください。

デフォルトのストレージエンジンとして InnoDB を使用したテストおよびベンチマーク

MySQL 5.1 以前から MySQL 5.5 以降へのアップグレードが完了する前でも、データベースサーバーまたはアプリケーションでデフォルトのストレージエンジンとして、InnoDB が正常に動作するかどうかをプレビューできます。以前の MySQL リリースでデフォルトのストレージエンジンとして InnoDB を設定するには、コマンド行で --default-storage-engine=InnoDB を指定するか、または my.cnf ファイルの [mysqld] セクションに default-storage-engine=innodb を追加してから、サーバーを再起動します。

デフォルトのストレージエンジンを変更しても、新たに作成されたテーブルしか影響を受けないため、アプリケーションのインストールおよび設定ステップをすべて実行して、すべてが正しくインストールされたことを確認します。次に、すべてのアプリケーション機能を実行して、データのロード、編集、およびクエリー機能がすべて動作することを確認します。テーブルが一部の MyISAM 固有の機能に依存している場合は、エラーが受信されます。エラーを回避するには、ENGINE=MyISAM 句を CREATE TABLE ステートメントに追加します (たとえば、全文検索に依存するテーブルは InnoDB テーブルではなく、MyISAM テーブルにする必要があります)。

ストレージエンジンについて慎重な決定を行わなかった場合に、特定のテーブルが InnoDB で作成されたときにどのように動作するのかをプレビューするには、テーブルごとに ALTER TABLE table_name ENGINE=InnoDB; コマンドを発行します。また、元のテーブルを配布せずに、テストクエリーおよびその他のステートメントを実行するには、次のようなコピーを作成します。

CREATE TABLE InnoDB_Table (...) ENGINE=InnoDB AS SELECT * FROM MyISAM_Table; 

MySQL 5.5 以上には、非常に多くの InnoDB のパフォーマンス拡張機能があるため、現実的なワークロードで完全なアプリケーションを使用したときのパフォーマンスについて正確な考察を得るには、最新の MySQL サーバーをインストールして、ベンチマークを実行してください。

完全なアプリケーションのライフサイクル (インストールから頻繁な使用まで)、およびサーバーの再起動をテストします。電源障害のシミュレーションを行うために、データベースの負荷が高いときにサーバープロセスを強制終了し、サーバーの再起動時にデータが正常にリカバリされるかどうかを確認します。

特に、マスターおよびスレーブ上でさまざまな MySQL バージョンやオプションを使用している場合は、レプリケーション構成をテストします。

InnoDB がデフォルトのストレージエンジンであるかどうかの確認

古い MySQL を使用して what-if テストを行うのか、最新の MySQL を使用して包括的なテストを行うのかに関係なく、InnoDB のステータスを確認する方法は、次のとおりです。

  • SHOW ENGINES; コマンドを発行して、さまざまな MySQL ストレージエンジンをすべて表示します。InnoDB 行で DEFAULT を探します。

  • InnoDB がまったく存在しない場合は、InnoDB のサポートなしでコンパイルされた mysqld バイナリがあるため、別のバイナリを入手する必要があります。

  • InnoDB は存在するが、無効になっている場合は、起動オプションおよび構成ファイルまで戻って、すべての skip-innodb オプションを削除します。

14.1.2 InnoDB の可用性チェック

使用中のサーバーで InnoDB がサポートされているかどうかを確認するには、SHOW ENGINES ステートメントを使用します。(InnoDB はデフォルトの MySQL ストレージエンジンになったため、サポートされない可能性があるのは、非常に特殊な環境の場合だけです。)

14.1.3 InnoDB の無効化

オラクルでは、ローカルシステム上で運用されている単一ユーザーの Wiki やブログから、パフォーマンスの限界を押し広げているハイエンドのアプリケーションまでの一般的なデータベースアプリケーションで優先されるストレージエンジンとして、InnoDB が推奨されています。MySQL 5.6 では、InnoDB が新しいテーブル用のデフォルトストレージエンジンです。

InnoDB テーブルを使用しない場合:

  • InnoDB ストレージエンジンを無効にするには、--innodb=OFF または --skip-innodb オプションを付けてサーバーを起動します。

    注記

    MySQL 5.6.21 の時点では、--skip-innodb オプションは引き続き機能しますが、非推奨となったため、使用されると警告が返されます。これは今後の MySQL リリースで削除されます。これは、そのシノニム (--innodb=OFF--disable-innodb など) にも適用されます。

  • デフォルトのストレージエンジンは InnoDB であるため、--default-storage-engine および --default-tmp-storage-engine を使用して、永続的なテーブルと TEMPORARY テーブルの両方についてデフォルトを別のエンジンに設定しないかぎり、サーバーは起動しません。

  • InnoDB 関連の information_schema テーブルでクエリーが実行されるときに、サーバーがクラッシュすることを回避するには、それらのテーブルに関連付けられたプラグインも無効にします。MySQL 構成ファイルの [mysqld] セクションで、次のように指定します。

    loose-innodb-trx=0
    loose-innodb-locks=0
    loose-innodb-lock-waits=0
    loose-innodb-cmp=0
    loose-innodb-cmp-per-index=0
    loose-innodb-cmp-per-index-reset=0
    loose-innodb-cmp-reset=0
    loose-innodb-cmpmem=0
    loose-innodb-cmpmem-reset=0
    loose-innodb-buffer-page=0
    loose-innodb-buffer-page-lru=0
    loose-innodb-buffer-pool-stats=0
    loose-innodb-metrics=0
    loose-innodb-ft-default-stopword=0
    loose-innodb-ft-inserted=0
    loose-innodb-ft-deleted=0
    loose-innodb-ft-being-deleted=0
    loose-innodb-ft-config=0
    loose-innodb-ft-index-cache=0
    loose-innodb-ft-index-table=0
    loose-innodb-sys-tables=0
    loose-innodb-sys-tablestats=0
    loose-innodb-sys-indexes=0
    loose-innodb-sys-columns=0
    loose-innodb-sys-fields=0
    loose-innodb-sys-foreign=0
    loose-innodb-sys-foreign-cols=0 

14.2 InnoDB の概念とアーキテクチャー

このセクションの情報では、InnoDB テーブルを使用することで大部分のパフォーマンスおよび機能を取得する際に役立つバックグラウンドが提供されます。対象者は次のとおりです。

  • 使い慣れていると思われる機能と、まったく新しい機能を説明するために、別のデータベースシステムから MySQL に切り替えている任意のユーザー。

  • InnoDB がデフォルトの MySQL ストレージエンジンになったために、MyISAM テーブルから InnoDB に移行している任意のユーザー。

  • InnoDB テーブルの設計上の考慮事項、パフォーマンスの特性、および拡張性を詳細なレベルで理解するために、アプリケーションアーキテクチャーまたはソフトウェアスタックを検討している任意のユーザー。

このセクションでは、次のことを学習します。

  • どのくらい厳密に InnoDBACID の原則に準拠しているのか。

  • どのように InnoDBトランザクションを実装するのか、およびどのようにトランザクションの内部動作と、使い慣れているその他のデータベースシステムを比較するのか。

  • どのように InnoDB が、クエリーおよび DML ステートメントが同じテーブルの読み取りと書き込みを同時に実行できる行レベルロックを実装するのか。

  • マルチバージョン並列処理制御 (MVCC) によって、適切な時間になる前にトランザクションがその他の各データを表示または変更することがどのように回避されるのか。

  • ディスク上の InnoDB 関連のオブジェクト (テーブルインデックステーブルスペースUndo ログ、および Redo ログ) の物理レイアウト。

14.2.1 MySQL および ACID モデル

ACID モデルは、ビジネスデータおよびミッションクリティカルなアプリケーションで重要となる信頼性の側面が強調されたデータベース設計原則のセットです。ソフトウェアのクラッシュやハードウェアの誤動作などの例外的な状況でも、データが破損せず、結果が歪曲されないように、MySQL には、ACID モデルに厳密に準拠した InnoDB ストレージエンジンなどのコンポーネントが含まれています。ACID に準拠した機能に依存していれば、一貫性チェックおよびクラッシュリカバリのメカニズムを再開発する必要がありません。追加のソフトウェアの保護手段、信頼性が最高のハードウェア、または少量のデータ損失や不整合に耐えることができるアプリケーションが備わっている場合は、ACID の信頼性の一部と引き換えに、パフォーマンスやスループットが向上するように MySQL の設定を調整できます。

次のセクションでは、どのように MySQL の機能 (特に InnoDB ストレージエンジン) が ACID モデルのカテゴリとやりとりするのかについて説明します。

  • A: 原子性。

  • C: 一貫性。

  • I:: 分離性。

  • D: 持続性。

原子性

ACID モデルの原子性の側面には、主に InnoDBトランザクションが関与しています。関連する MySQL の機能は次のとおりです。

  • 自動コミット設定。

  • COMMIT ステートメント。

  • ROLLBACK ステートメント。

  • INFORMATION_SCHEMA テーブルの運用データ。

一貫性

ACID モデルの一貫性の側面には、主にクラッシュからデータを保護するための内部的な InnoDB 処理が関与しています。関連する MySQL の機能は次のとおりです。

分離性

ACID モデルの分離性の側面には、主に InnoDBトランザクション (特に、各トランザクションに適用される分離レベル) が関与しています。関連する MySQL の機能は次のとおりです。

  • 自動コミット設定。

  • SET ISOLATION LEVEL ステートメント。

  • InnoDBロックの低レベルの詳細。これらの詳細は、パフォーマンスチューニング時に INFORMATION_SCHEMA テーブルから参照します。

持続性

ACID モデルの持続性の側面には、特定のハードウェア構成とやりとりする MySQL ソフトウェアの機能が関与しています。CPU、ネットワーク、およびストレージデバイスの性能に応じて多くの可能性が考えられるため、具体的なガイドラインを示す際は、この側面がもっとも複雑になります。(これらのガイドラインに従うことは、新しいハードウェアを購入するという形になる場合があります。)関連する MySQL の機能は次のとおりです。

  • innodb_doublewrite 構成オプションでオンとオフが切り替えられる InnoDB二重書き込みバッファー

  • innodb_flush_log_at_trx_commit 構成オプション。

  • sync_binlog 構成オプション。

  • innodb_file_per_table 構成オプション。

  • ストレージデバイス内の書き込みバッファー (ディスクドライブ、SSD、RAID アレイなど)。

  • ストレージデバイス内のバッテリーでバックアップされるキャッシュ。

  • MySQL を実行する際に使用されるオペレーティングシステム (特に、fsync() システムコールでのサポート)。

  • MySQL サーバーを実行し、MySQL データを格納するすべてのコンピュータサーバーおよびストレージデバイスへの電力を保護する無停電電源装置 (UPS)。

  • バックアップ方針 (頻度、バックアップのタイプ、バックアップの保存期間など)。

  • 分散型またはホスト型のデータアプリケーションの場合、MySQL サーバー用のハードウェアが配置されているデータセンター、およびデータセンター間のネットワーク接続の特定の特性。

14.2.2 InnoDB のトランザクションモデルおよびロック

トランザクションおよびロックは InnoDB ストレージエンジンに関連するため、大規模、高負荷、または高信頼性のデータベースアプリケーションを実装したり、別のデータベースシステムから大量のコードを移植したり、MySQL のパフォーマンスを調整したりするには、これらの概念を理解する必要があります。

InnoDB トランザクションモデルの目標は、マルチバージョンデータベースの最高の特性を従来の二相ロックと組み合わせることです。InnoDB は、行レベルでロックを行い、デフォルトではクエリーを Oracle 式の非ロックの一貫性読み取りとして実行します。InnoDB のロック情報は非常に高い空間効率で格納されるため、ロックのエスカレーションは必要ありません。一般に、何人かのユーザーは、InnoDB テーブル内のすべての行、または行のランダムなサブセットをロックすることが許可されています。これにより、InnoDB のメモリーが使い果たされることはありません。

InnoDB では、すべてのユーザーアクティビティーがトランザクション内部で発生します。自動コミットモードが有効になっている場合は、各 SQL ステートメント自体に単一のトランザクションが生成されます。MySQL は、デフォルトで新しい接続のセッション開始時に自動コミットを有効にするため、各 SQL ステートメントからエラーが返されなかった場合に、そのステートメントのあとでコミットを実行します。ステートメントからエラーが返された場合、コミットまたはロールバックの動作はそのエラーによって異なります。セクション14.19.4「InnoDB のエラー処理」を参照してください。

自動コミットが有効になっているセッションでは、明示的な START TRANSACTION または BEGIN ステートメントで起動し、COMMIT または ROLLBACK ステートメントで終了することで、複数ステートメントのトランザクションを実行できます。セクション13.3.1「START TRANSACTION、COMMIT、および ROLLBACK 構文」を参照してください。

SET autocommit = 0 でセッション内の自動コミットモードを無効にすると、そのセッションでは常にトランザクションが開かれた状態になります。COMMIT または ROLLBACK ステートメントは現在のトランザクションを終了し、新しいセッションを開始します。

COMMIT は、現在のトランザクション内で行われた変更は永続的であり、その他のセッションから表示できることを意味します。反対に、ROLLBACK ステートメントは、現在のトランザクションによって行われたすべての変更を取り消します。COMMITROLLBACK は両方とも、現在のトランザクション中に設定されたすべての InnoDB ロックを解除します。

SQL:1992 のトランザクション分離レベルに関しては、デフォルトの InnoDB レベルは REPEATABLE READ です。InnoDB では、SQL 標準に記載された 4 つのトランザクション分離レベル (READ UNCOMMITTEDREAD COMMITTEDREPEATABLE READSERIALIZABLE) がすべて提供されます。

ユーザーは SET TRANSACTION ステートメントを使用して単一のセッションまたは後続のすべての接続の分離レベルを変更できます。すべての接続に対するサーバーのデフォルトの分離レベルを設定するには、コマンド行上、またはオプションファイル内で --transaction-isolation オプションを使用します。分離レベルおよびレベル設定構文についての詳細は、セクション13.3.6「SET TRANSACTION 構文」を参照してください。

InnoDB では、通常、行レベルロックでネクストキーロックが使用されます。つまり、InnoDB はインデックスレコードのほかに、インデックスレコードの前のギャップもロックすることで、インデックス付きの値がツリーデータ構造内のそのギャップに挿入されるその他のセッションによって挿入されることをブロックできます。ネクストキーロックは、インデックスレコードとその前のギャップをロックするロックを参照します。ギャップロックは、いくつかのインデックスレコードの前のギャップのみをロックするロックを参照します。

行レベルロック、およびギャップロックが無効になる状況についての詳細は、セクション14.2.6「InnoDB のレコード、ギャップ、およびネクストキーロック」を参照してください。

14.2.3 InnoDB のロックモード

InnoDB では、2 つのロックタイプ (共有 (S) ロック排他 (X) ロック) がある標準の行レベルロックが実装されます。レコード、ギャップ、およびネクストキーの各ロックタイプについては、セクション14.2.6「InnoDB のレコード、ギャップ、およびネクストキーロック」を参照してください。

  • 共有 (S) ロックでは、ロックを保持するトランザクションによる行の読み取りが許可されます。

  • 排他 (X) ロックでは、ロックを保持するトランザクションによる行の更新または削除が許可されます。

トランザクション T1 が行 r に対する共有 (S) ロックを保持している場合、別のトランザクション T2 からの行 r に対するロック要求は次のように処理されます。

  • T2 による S ロックに対するリクエストは、すぐに付与できます。結果として、T1T2 の両方が r 上で S ロックを保持します。

  • T2 による X ロックに対するリクエストは、すぐに付与できません。

トランザクション T1 が行 r 上で排他 (X) ロックを保持している場合は、r 上のいずれかのタイプのロックに対する一部の個別のトランザクション T2 からのリクエストは、すぐに付与できません。代わりに、トランザクション T2 は、行 r 上でトランザクション T1 のロックが解放されるまで待機する必要があります。

インテンションロック

さらに、InnoDB では、レコードロックとテーブル全体のロックが共存することを許可する複数粒度ロックもサポートされています。複数粒度レベルでのロックを実用的にするために、インテンションロックと呼ばれる追加のロックタイプが使用されます。インテンションロックとは、あとでトランザクションがそのテーブル内の行で必要となるロックのタイプ (共有または排他) を示す InnoDB のテーブルロックです。トランザクション T がテーブル t 上に指定されたタイプのロックをリクエストしたと仮定すると、InnoDB で使用されるインテンションロックには、次の 2 つタイプがあります。

  • インテンション共有 (IS): トランザクション T は意図的に、テーブル t 内の各行に S ロックを設定します。

  • インテンション排他 (IX): トランザクション T は意図的に、これらの行に X ロックを設定します。

たとえば、SELECT ... LOCK IN SHARE MODEIS ロックを設定し、SELECT ... FOR UPDATEIX ロックを設定します。

インテンションロックの手順は次のとおりです。

  • トランザクションがテーブル t のある行の S ロックを取得するには、まず tIS またはそれより強いロックを取得する必要があります。

  • トランザクションがある行の X ロックを取得するには、まず tIX ロックを取得する必要があります。

これらのルールをまとめる際は、次に示すロックタイプ互換性マトリクスを使用すると便利です。

 XIXSIS
X競合競合競合競合
IX競合互換競合互換
S競合競合互換互換
IS競合互換互換互換

ロックに既存のロックとの互換性がある場合は、リクエスト元のトランザクションにロックが付与されますが、既存のロックと競合している場合は、ロックが付与されません。トランザクションは、競合している既存のロックが解放されるまで待機します。ロックリクエストが既存のロックと競合し、デッドロックが発生するために付与できない場合は、エラーが発生します。

したがって、インテンションロックでは、完全なテーブルリクエスト (LOCK TABLES ... WRITE など) 以外は何もブロックされません。IX および IS ロックの主な目的は、だれかが行をロックしていることや、テーブル内の行をロックしようとしていることを示すことです。

デッドロックの例

次の例は、ロックリクエストによってデッドロックが発生したときに、どのようにエラーが発生するのかを示しています。この例には、A と B の 2 つのクライアントが登場します。

最初に、クライアント A が行を 1 つ含むテーブルを作成し、トランザクションを開始します。トランザクション内で、A は共有モードで選択した行で S ロックを取得します。

mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;Query OK, 0 rows affected (1.07 sec)
mysql> INSERT INTO t (i) VALUES(1);Query OK, 1 row affected (0.09 sec)
mysql> START TRANSACTION;Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;+------+
| i |
+------+
| 1 |
+------+
1 row in set (0.10 sec)

次に、クライアント B がトランザクションを開始し、テーブルから行を削除しようとします。

mysql> START TRANSACTION;Query OK, 0 rows affected (0.00 sec)
mysql> DELETE FROM t WHERE i = 1;

削除操作を行うには、X ロックが必要です。クライアント A が保持している S ロックとの互換性がないために、ロックを付与できません。そのため、リクエストはその行のロックリクエストのキューに入れられ、クライアント B はブロックされます。

最後に、クライアント A もテーブルから行を削除しようとします。

mysql> DELETE FROM t WHERE i = 1;ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

クライアント A は行を削除するために X ロックが必要であるため、ここでデッドロックが発生します。ただし、クライアント B はすでに X ロックに対するリクエストを持っていて、クライアント A がその S ロックを解放するまで待機しているため、そのロックリクエストを付与することはできません。B による X ロックに対する以前のリクエストが原因で、A が保持している S ロックを X ロックにアップグレードすることもできません。その結果、InnoDB はクライアントのいずれかに対してエラーを生成し、そのロックを解放します。クライアントは、次のエラーを返します。

ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

この時点で、ほかのクライアントに対するロックリクエストを付与できるようになり、テーブルから行が削除されます。

注記

InnoDB Monitor の出力の LATEST DETECTED DEADLOCK セクションには、TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH, WE WILL ROLL BACK FOLLOWING TRANSACTION というメッセージが含まれます。これは、待機リスト上のトランザクション数が 200 の制限に達したことを示します。この制限は、LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK で定義されます。200 個のトランザクションを超える待機リストはデッドロックとして処理され、待機リストをチェックしようとするトランザクションはロールバックされます。

ロックスレッドが待機リスト上のトランザクションが所有する 1,000,000 個を超えるロックを参照する必要がある場合も、同じエラーが発生する可能性があります。1,000,000 個のロック制限は、LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK で定義されます。

14.2.4 一貫性非ロック読み取り

一貫性読み取りとは、InnoDB がマルチバージョンを使用して、ある時点でのデータベースのスナップショットをクエリーに提供することを意味します。クエリーには、その時点よりも前にコミットされたトランザクションによる変更のみが表示され、その時点よりもあとのトランザクションまたはコミットされていないトランザクションによる変更は表示されません。このルールの例外として、同じトランザクション内の以前のステートメントによる変更はクエリーに表示されます。この例外によって、次のような異常が発生します。テーブル内の一部の行を更新すると、更新された行の最新バージョンが SELECT に表示されますが、いずれかの行の旧バージョンも表示される可能性があります。その他のセッションで同じテーブルが同時に更新される場合、その異常は、データベースに存在しない状態でテーブルが表示される可能性があることを意味します。

トランザクション分離レベルREPEATABLE READ (デフォルトのレベル) である場合は、同じトランザクション内のすべての一貫性読み取りで、そのトランザクション内の最初のこのような読み取りで確立されたスナップショットが読み取られます。現在のトランザクションをコミットしたあとに、新しいクエリーを発行すると、クエリーの新しいスナップショットを取得できます。

分離レベルが READ COMMITTED の場合は、トランザクション内の各一貫性読み取りで、独自の新しいスナップショットが設定され、読み取られます。

一貫性読み取りは、InnoDBREAD COMMITTED および REPEATABLE READ 分離レベルで SELECT ステートメントを処理する際のデフォルトモードです。一貫性読み取りではアクセスされるテーブル上にロックが設定されないため、その他のセッションも、そのテーブル上で一貫性読み取りが実行されるときと同時に、それらのテーブルを自由に変更できます。

デフォルトの REPEATABLE READ 分離レベルで実行していると仮定します。一貫性読み取り (つまり、通常の SELECT ステートメント) を発行すると、InnoDB は、クエリーがデータベースを参照するときの基準となるタイムポイントをトランザクションに付与します。タイムポイントが割り当てられたあとに、別のトランザクションが行を削除してコミットした場合は、その行が削除済みとして表示されません。挿入および更新も同様に処理されます。

注記

データベースの状態のスナップショットは、トランザクション内の SELECT ステートメントに適用されますが、DML ステートメントには必ずしも適用されるとは限りません。一部の行を挿入または変更してから、そのトランザクションをコミットする場合は、そのセッションでクエリーが実行される可能性がない場合でも、別の並列実行 REPEATABLE READ トランザクションから発行された DELETE または UPDATE ステートメントによって、コミットされたばかりの行が影響を受ける可能性があります。トランザクションによって別のトランザクションでコミットされた行が更新または削除されると、これらの変更を現在のトランザクションに表示できるようになります。たとえば、次のような状況が発生する可能性があります。

SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz'; -- Returns 0: no rows match.
DELETE FROM t1 WHERE c1 = 'xyz'; -- Deletes several rows recently committed by other transaction.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc'; -- Returns 0: no rows match.
UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc'; -- Affects 10 rows: another txn just committed 10 rows with 'abc' values.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba'; -- Returns 10: this txn can now see the rows it just updated.

トランザクションをコミットしてから、別の SELECT または START TRANSACTION WITH CONSISTENT SNAPSHOT を実行すると、タイムポイントを進めることができます。

これは、マルチバージョン並列処理制御と呼ばれます。

次の例では、セッション B が挿入をコミットし、セッション A も同様にコミットした場合にのみ、B によって挿入された行が A に表示されます。これにより、タイムポイントが B のコミットよりも先に進みます。

 Session A Session B SET autocommit=0; SET autocommit=0;
time
| SELECT * FROM t;
| empty set
| INSERT INTO t VALUES (1, 2);
|
v SELECT * FROM t; empty set COMMIT; SELECT * FROM t; empty set COMMIT; SELECT * FROM t; --------------------- | 1 | 2 | --------------------- 1 row in set

データベースの最新状態を確認する場合は、READ COMMITTED 分離レベルとロック読み取りのいずれかを使用します。

SELECT * FROM t LOCK IN SHARE MODE;

分離レベルが READ COMMITTED の場合は、トランザクション内の各一貫性読み取りで、独自の新しいスナップショットが設定され、読み取られます。LOCK IN SHARE MODE の場合は、代わりにロック読み取りが発生します。SELECT は、最新の行を含むトランザクションが終了するまでブロックされます (セクション14.2.5「ロック読み取り (SELECT ... FOR UPDATE および SELECT ... LOCK IN SHARE MODE)」を参照)。

特定の DDL ステートメントでは、一貫性読み取りが機能しません。

  • DROP TABLE では、MySQL が削除されたテーブルを使用できず、そのテーブルは InnoDB によって破棄されるため、一貫性読み取りが機能しません。

  • ALTER TABLE では、そのステートメントで元のテーブルの一時コピーが作成され、元のテーブルは一時コピーが構築されるときに削除されるため、一貫性読み取りが機能しません。トランザクション内で一貫性読み取りを再発行しても、新しいテーブル内の行はトランザクションのスナップショット取得されたときには存在していなかったため、表示できません。MySQL 5.6.6 の時点では、この場合に、トランザクションからTable definition has changed, please retry transactionという ER_TABLE_DEF_CHANGED エラーが返されます。

FOR UPDATE または LOCK IN SHARE MODE を指定しない INSERT INTO ... SELECTUPDATE ... (SELECT)CREATE TABLE ... SELECT などの句での選択では、読み取りのタイプが異なります。

  • デフォルトでは、InnoDB はより強固なロックを使用し、SELECT 部分は READ COMMITTED と同様に機能します。この場合、同じトランザクション内でも、各一貫性読み取りで独自の新しいスナップショットが設定され、読み取られます。

  • このような場合に一貫性読み取りを使用するには、innodb_locks_unsafe_for_binlog オプションを有効にし、トランザクションの分離レベルを READ UNCOMMITTEDREAD COMMITTED、または REPEATABLE READ (つまり、SERIALIZABLE 以外のすべて) に設定します。この場合、選択したテーブルから読み取られた行には、ロックが設定されません。

14.2.5 ロック読み取り (SELECT ... FOR UPDATE および SELECT ... LOCK IN SHARE MODE)

データのクエリーを実行してから、同じトランザクション内で関連データを挿入または更新する場合は、通常の SELECT ステートメントで十分な保護が提供されません。ほかのトランザクションは、クエリーが実行されたばかりの同じ行を更新または削除できます。InnoDB では、追加の安全性が提供される 2 つのタイプのロック読み取りがサポートされています。

  • SELECT ... LOCK IN SHARE MODE は、読み取られるすべての行に共有モードのロックを設定します。ほかのセッションもその行を読み取ることができますが、トランザクションがコミットするまで変更することはできません。これらの行のいずれかがコミットされていない別のトランザクションによって変更された場合、クエリーはそのトランザクションが終了するまで待機してから、最新の値を使用します。

  • 検索でインデックスレコードが見つかった場合、SELECT ... FOR UPDATE は、行および関連付けられたすべてのエントリをロックします。この動作は、これらの行に UPDATE ステートメントを発行した場合と同じです。ほかのトランザクションは、これらの行の更新、SELECT ... LOCK IN SHARE MODE の実行、または特定のトランザクション分離レベルでのデータの読み取りからブロックされます。一貫性読み取りでは、読み取られたビュー内に存在するレコードに設定されたロックはすべて無視されます。(古いバージョンのレコードはロックできません。レコードのインメモリーコピー上の Undo ログに適用することで、再構築されます。)

これらの句は、主に、単一のテーブル内または複数のテーブルに分割された状態で、ツリー構造またはグラフ構造のデータを処理する際に役立ちます。エッジまたはツリー分岐をある場所から別の場所にトラバースしても、これらのポインタに戻ってその値を変更する権利を保有しています。

トランザクションがコミットまたはロールバックされると、LOCK IN SHARE MODE および FOR UPDATE クエリーで設定されたすべてのロックが解放されます。

注記

SELECT FOR UPDATE を使用した更新対象の行のロックは、START TRANSACTION でトランザクションを開始するか、autocommit を 0 に設定することで、自動コミットが無効になっている場合にのみ適用されます。自動コミットが有効になっている場合は、指定に一致する行がロックされません。

使用例

child テーブルに新しい行を挿入し、子の行が parent テーブル内に親の行を持っていることを確認すると仮定します。アプリケーションコードを使用して、この操作シーケンス全体の参照整合性を確保できます。

まず、一貫性読み取りを使用して、PARENT テーブルでクエリーを実行し、親の行が存在することを確認します。CHILD テーブルに子の行を安全に挿入できますか。気付かないうちに、その他の一部のセッションで、SELECTINSERT との間に親の行が削除された可能性もあるため、できません。

このような問題の可能性を回避するには、LOCK IN SHARE MODE を使用して SELECT を実行します。

SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

LOCK IN SHARE MODE クエリーから「Jones」という親が返されたら、CHILD テーブルに子のレコードを安全に追加し、トランザクションをコミットできます。PARENT テーブル内のアプリケーション行で読み取りまたは書き込みを行おうとするトランザクションは、ユーザーが完了するまで (つまり、すべてのテーブル内のデータが一貫性のある状態になるまで) 待機します。

もう 1 つの例では、CHILD テーブルに追加された各子に一意の識別子を割り当てる際に使用される CHILD_CODES テーブル内の整数カウンタフィールドを検討します。一貫性読み取りまたは共有モード読み取りを使用すると、データベースの 2 人のユーザーが同じカウンタ値を参照する可能性があり、2 つのトランザクションが同じ識別子を持つ行を CHILD テーブルに追加しようとすると、重複キーのエラーが発生するため、カウンタの現在の値を読み取る際には使用しないでください。

ここで、2 人のユーザーがカウンタを同時に読み取る場合、少なくとも 1 人のユーザーがカウンタを更新しようとするとデッドロックが発生するため、LOCK IN SHARE MODE は適切な解決策ではありません。

カウンタの読み取りおよび増分を実装するには、まず FOR UPDATE を使用してカウンタのロック読み取りを実行してから、カウンタを増分します。例:

SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;

SELECT ... FOR UPDATE は使用可能な最新データを読み取り、読み取られる各行上に排他ロックを設定します。したがって、検索された SQL UPDATE によって行上に設定される場合と同じロックが設定されます。

前述の説明は、単に SELECT ... FOR UPDATE がどのように機能するのかを示した例です。MySQL では、テーブルへの単一アクセスを使用するだけで、一意の識別子を生成する特定のタスクを実現できます。

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();

この SELECT ステートメントは、単に (現在の接続に固有の) 識別子情報を取得するだけです。どのテーブルにもアクセスしません。

14.2.6 InnoDB のレコード、ギャップ、およびネクストキーロック

InnoDB のレコードレベルのロックには、レコードロック、ギャップロック、ネクストキーロックなどの複数のタイプがあります。共有ロック、排他ロック、およびインテンションロックについては、セクション14.2.3「InnoDB のロックモード」を参照してください。

  • レコードロック: これはインデックスレコードのロックです。

  • ギャップロック: これはインデックスレコード間にあるギャップのロック、または先頭のインデックスレコードの前や末尾のインデックスレコードのあとにあるギャップのロックです。

  • ネクストキーロック: これはインデックスレコードに対するレコードロックと、そのインデックスレコードの前にあるギャップに対するギャップロックとを組み合わせたものです。

レコードロック

レコードロックでは、テーブルにインデックスが定義されていなくても必ず、インデックスレコードがロックされます。このような場合は、InnoDB によって非表示のクラスタ化されたインデックスが作成され、このインデックスを使用してレコードロックが行われます。セクション14.2.13.2「クラスタインデックスとセカンダリインデックス」を参照してください。

ネクストキーロック

デフォルトでは、InnoDBREPEATABLE READ トランザクション分離レベルで動作し、innodb_locks_unsafe_for_binlog システム変数は無効になっています。この場合、InnoDB はネクストキーロックを使用して検索およびインデックススキャンを行うため、ファントム行の発生を回避できます (セクション14.2.7「ネクストキーロックによるファントム問題の回避」を参照)。

ネクストキーロックは、インデックス行ロックとギャップロックを組み合わせたものです。InnoDB は、テーブルインデックスを検索またはスキャンするときに、生成されたインデックスレコード上に共有ロックまたは排他ロックを設定するという方法で、行レベルロックを実行します。したがって、行レベルロックは、実際にはインデックスレコードロックです。さらに、あるインデックスレコードに対するネクストキーロックによって、そのインデックスレコードの前のギャップも影響を受けます。つまり、ネクストキーロックは、インデックスレコードロックと、そのインデックスレコードの前のギャップに対するギャップロックとを組み合わせたものです。あるセッションがインデックス内のレコード R 上に共有ロックまたは排他ロックを持っている場合は、別のセッションがインデックスの順番で R の直前にあるギャップに新しいインデックスレコードを挿入できません。

あるインデックスに値 10、11、13、20 が含まれているとします。このインデックスでは、次の間隔をカバーするネクストキーロックが使用される可能性があります。ここで、() は間隔の端点が含まれないことを表し、[] は間隔の端点が含まれることを表します。

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

最後の間隔ではネクストキーロックによって、インデックス内の最大値を上回るギャップ、およびインデックス内の実際のどの値よりも大きい値を持つ最小上限の擬似レコードがロックされます。最小上限は実際のインデックスレコードではないため、事実上、このネクストキーロックによってロックされるのは、最大インデックス値のあとにあるギャップのみです。

ギャップロック

前のセクションで示したネクストキーロックの例は、ギャップの範囲が単一のインデックス値、複数のインデックス値、または空になる場合もあることを示しています。

一意のインデックスを使用して一意の行を検索することで行をロックするステートメントでは、ギャップロックは必要ありません。(これには、検索条件に複数カラムの一意のインデックスの一部のカラムのみが含まれるケースは含まれません。この場合は、ギャップロックが発生します。)たとえば、id カラムに一意のインデックスが設定されている場合、次のステートメントで使用されるのは id の値が 100 の行に対するインデックスレコードロックだけとなり、ほかのセッションがそのレコードの前にあるギャップに行を挿入するかどうかは問題ではなくなります。

SELECT * FROM child WHERE id = 100;

id にインデックスが設定されていなかったり、一意でないインデックスが設定されていたりすると、このステートメントで先行するギャップがロックされます。

INSERT 操作では行の挿入前に、挿入インテンションギャップロックと呼ばれる一種のギャップロックが設定されます。このロックは、同じインデックスギャップに挿入する複数のトランザクションは、そのギャップ内の同じ場所に挿入しなければ相互に待機する必要がないように、意図的に挿入することを示しています。値が 4 と 7 のインデックスレコードが存在すると仮定します。それぞれ値 5 と 6 の挿入を試みる別々のトランザクションは、挿入される行の排他ロックを取得する前に挿入インテンションロックを使用して、4 と 7 の間にあるギャップをロックしますが、行の競合が発生しないため相互にブロックされません。インテンションロックについての詳細は、セクション14.2.3「InnoDB のロックモード」を参照してください。

さまざまなトランザクションによってギャップ上に競合するロックを保持できることも、ここで注目するべき点です。たとえば、トランザクション A はギャップ上に共有ギャップロック (ギャップ S ロック) を保持できる一方で、トランザクション B は同じギャップ上に排他ギャップロック (ギャップ X ロック) を保持します。競合するギャップロックが許可される理由は、レコードがインデックスからパージされる場合に、さまざまなトランザクションによってレコード上に保持されたギャップロックをマージする必要があるためです。

InnoDB のギャップロックは、単に抑制的です。つまり、ほかのトランザクションによるギャップへの挿入が停止されるだけです。したがって、ギャップ X ロックの効果はギャップ S ロックと同じです。

ギャップロックの無効化

ギャップロックは明示的に無効化できます。これは、トランザクション分離レベルを READ COMMITTED に変更するか、または innodb_locks_unsafe_for_binlog システム変数 (現在は非推奨です) を有効にすると発生します。このような状況では、ギャップロックは検索およびインデックススキャン時に無効化され、外部キー制約チェックおよび重複キーチェック時にのみ使用されます。

READ COMMITTED 分離レベルを使用するか、innodb_locks_unsafe_for_binlog を有効にした場合の効果はほかにもあります。一致しない行のレコードロックは、MySQL による WHERE 条件の評価が完了すると解放されます。UPDATE ステートメントの場合、InnoDB は最後にコミットされたバージョンが MySQL に返されるように、半一貫性読み取りを実行します。これにより、MySQL はその行が UPDATEWHERE 条件に一致するかどうかを判断できます。

14.2.7 ネクストキーロックによるファントム問題の回避

同じクエリーでさまざまな時間にさまざまな行のセットが生成されると、いわゆるファントムの問題がトランザクション内で発生します。たとえば、SELECT が 2 回実行されたが、1 回目には返されなかった行が 2 回目には返された場合、その行がファントム行です。

child テーブルの id カラム上にインデックスがあり、識別子の値が 100 よりも大きいすべての行をテーブルから読み取り、選択された行の一部のカラムをあとで更新するという意図でロックすると仮定します。

SELECT * FROM child WHERE id > 100 FOR UPDATE;

クエリーでは、id が 100 よりも大きい最初のレコードからインデックスがスキャンされます。このテーブルには id の値が 90 と 102 の行が格納されているものとします。スキャン範囲内のインデックスレコード上に設定されたロックによって、ギャップ (この場合のギャップは 90 から 102 まで) への挿入がロックアウトされていない場合は、別のセッションが id が 101 の新しい行をそのテーブルに挿入できます。同じトランザクション内で同じ SELECT を実行すると、クエリーから返された結果セット内に、id が 101 の新しい行 (ファントム) が含まれています。一連の行をデータ項目とみなせば、この新しいファントムの子は、「トランザクション中は読み取られるデータが変更されないようにトランザクションを実行できるべきである」というトランザクションの分離原則に違反しています。

ファントムの発生を回避できるように、InnoDB では通常、インデックス行ロックとギャップロックを組み合わせたネクストキーロックと呼ばれるアルゴリズムが使用されます。InnoDB は、テーブルインデックスを検索またはスキャンするときに、生成されたインデックスレコード上に共有ロックまたは排他ロックを設定するという方法で、行レベルロックを実行します。したがって、行レベルロックは、実際にはインデックスレコードロックです。さらに、あるインデックスレコードに対するネクストキーロックによって、そのインデックスレコードの前のギャップも影響を受けます。つまり、ネクストキーロックは、インデックスレコードロックと、そのインデックスレコードの前のギャップに対するギャップロックとを組み合わせたものです。あるセッションがインデックス内のレコード R 上に共有ロックまたは排他ロックを持っている場合は、別のセッションがインデックスの順番で R の直前にあるギャップに新しいインデックスレコードを挿入できません。

InnoDB はインデックスをスキャンするときに、インデックス内の最後のレコードのあとのギャップをロックすることもできます。前述の例では、まさにそれが行われています。id が 100 よりも大きいテーブルへの挿入が回避されるように、InnoDB で設定されたロックには、id 値 102 のあとのギャップに対するロックが含まれています。

ネクストキーロックを使用すると、アプリケーションに一意性チェックを実装できます。共有モードでデータを読み取るときに、挿入される行の重複が見られなければ、行を安全に挿入でき、読み取り中に後続の行に設定されたネクストキーロックによって、任意のユーザーによる重複行の挿入が回避されることを確認できます。したがって、ネクストキーロックを使用すれば、テーブル内に存在しないものもロックできます。

ギャップロックは、セクション14.2.6「InnoDB のレコード、ギャップ、およびネクストキーロック」で説明した方法で無効にすることができます。ギャップロックが無効になっていると、ほかのセッションが新しい行をギャップに挿入できるため、ファントムの問題が発生する可能性があります。

14.2.8 InnoDB のさまざまな SQL ステートメントで設定されたロック

一般に、ロック読み取りUPDATE、または DELETE では、SQL ステートメントの処理時にスキャンされるすべてのインデックスレコード上に、レコードロックが設定されます。 行を除外する WHERE 条件がステートメント内に存在するかどうかは、関係ありません。InnoDB には正確な WHERE 条件が記憶されませんが、スキャンされたインデックスの範囲は認識されます。通常、ロックはレコードの直前にあるギャップへの挿入もブロックするネクストキーロックです。ただし、ギャップロックは明示的に無効にすることができます。これにより、ネクストキーロックが使用されなくなります。詳細は、セクション14.2.6「InnoDB のレコード、ギャップ、およびネクストキーロック」を参照してください。トランザクション分離レベルによって、どのロックが設定されるのかも影響を受けます。セクション13.3.6「SET TRANSACTION 構文」を参照してください。

検索でセカンダリインデックスが使用され、設定されるインデックスレコードのロックが排他的である場合、InnoDB は対応するクラスタ化されたインデックスレコードを取得し、それらにロックを設定することも行います。

共有ロックと排他ロックの違いについては、セクション14.2.3「InnoDB のロックモード」を参照してください。

ステートメントに適したインデックスがなく、MySQL がステートメントを処理するためにテーブル全体をスキャンする必要がある場合は、テーブルのすべての行がロックされます。その結果、そのテーブルへのほかのユーザーによるすべての挿入がブロックされます。クエリーで不必要に複数の行がスキャンされないように、適切なインデックスを作成することが重要です。

SELECT ... FOR UPDATE または SELECT ... LOCK IN SHARE MODE では、スキャンされた行についてはロックが取得され、WHERE 句に指定された条件を満たさないなどの理由で結果セットに含める対象から除外された行については、ロックが解放されることが予想されます。ただし場合によっては、クエリーの実行中に結果行とその元のソースとの関係が失われたために、行のロックがすぐに解除されない可能性もあります。たとえば UNION では、スキャン (およびロック) されたテーブル内の行が、結果セットに含める対象となるかどうかの評価前に、一時テーブルに挿入される可能性があります。この状況では、一時テーブル内の行と元のテーブル内の行との関係は失われているため、クエリー実行が終了するまで後者の行のロックは解除されません。

InnoDB は、次のように特定のロックタイプを設定します。

  • SELECT ... FROM は一貫性読み取りであり、データベースのスナップショットを読み取り、トランザクションの分離レベルが SERIALIZABLE に設定されなければロックを設定しません。SERIALIZABLE レベルの場合、検索で見つかったインデックスレコード上に共有ネクストキーロックが設定されます。

  • SELECT ... FROM ... LOCK IN SHARE MODE では、検索で見つかったすべてのインデックスレコード上に共有ネクストキーロックが設定されます。

  • SELECT ... FROM ... FOR UPDATE は、検索で見つかったインデックスレコードに対して、ほかのセッションが SELECT ... FROM ... LOCK IN SHARE MODE を実行したり、特定のトランザクション分離レベルで読み取ったりすることをブロックします。一貫性読み取りでは、読み取られたビュー内に存在するレコードに設定されたロックはすべて無視されます。

  • UPDATE ... WHERE ... は、検索で見つかったすべてのレコード上に排他ネクストキーロックを設定します。

  • DELETE FROM ... WHERE ... は、検索で見つかったすべてのレコード上に排他ネクストキーロックを設定します。

  • INSERT は、挿入される行に排他ロックを設定します。このロックは、ネクストキーロックではなくインデックスレコードロックである (つまり、ギャップロックが存在しない) ため、ほかのセッションが挿入された行の前にあるギャップに挿入することは回避されません。

    行の挿入前に、挿入インテンションギャップロックと呼ばれる一種のギャップロックが設定されます。このロックは、同じインデックスギャップに挿入する複数のトランザクションは、そのギャップ内の同じ場所に挿入しなければ相互に待機する必要がないように、意図的に挿入することを示しています。値が 4 と 7 のインデックスレコードが存在すると仮定します。それぞれ値 5 と 6 の挿入を試みる別々のトランザクションは、挿入される行の排他ロックを取得する前に挿入インテンションロックを使用して、4 と 7 の間にあるギャップをロックしますが、行の競合が発生しないため相互にブロックされません。

    重複キーエラーが発生すると、重複インデックスレコード上の共有ロックが設定されます。複数のセッションが同じ行を挿入しようとしているときに、別のセッションがすでに排他ロックを取得していた場合は、このように共有ロックを使用することでデッドロックが発生する可能性があります。これは、別のセッションがその行を削除した場合に発生する可能性があります。InnoDB テーブル t1 の構造が次のようになっているとします。

    CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;

    次に、3 つのセッションが次の処理を順番に実行するものとします。

    セッション 1:

    START TRANSACTION;
    INSERT INTO t1 VALUES(1);

    セッション 2:

    START TRANSACTION;
    INSERT INTO t1 VALUES(1);

    セッション 3:

    START TRANSACTION;
    INSERT INTO t1 VALUES(1);

    セッション 1:

    ROLLBACK;

    セッション 1 による最初の処理では、行の排他ロックが取得されます。セッション 2 と 3 の処理ではどちらも重複キーエラーが発生し、どちらのセッションも行の共有ロックをリクエストします。セッション 1 はロールバック時に行の排他ロックを解放し、キュー内のセッション 2 と 3 の共有ロックリクエストが付与されます。この時点でセッション 2 と 3 でデッドロックが発生します。どちらも他方が保持している共有ロックのために、行の排他ロックを取得できません。

    キー値が 1 の行がテーブルに含まれている場合も似たような状況が発生し、3 つのセッションが次の処理を順番に実行します。

    セッション 1:

    START TRANSACTION;
    DELETE FROM t1 WHERE i = 1;

    セッション 2:

    START TRANSACTION;
    INSERT INTO t1 VALUES(1);

    セッション 3:

    START TRANSACTION;
    INSERT INTO t1 VALUES(1);

    セッション 1:

    COMMIT;

    セッション 1 による最初の処理では、行の排他ロックが取得されます。セッション 2 と 3 の処理ではどちらも重複キーエラーが発生し、どちらのセッションも行の共有ロックをリクエストします。セッション 1 はコミット時に行の排他ロックを解放し、キュー内のセッション 2 と 3 の共有ロックリクエストが付与されます。この時点でセッション 2 と 3 でデッドロックが発生します。どちらも他方が保持している共有ロックのために、行の排他ロックを取得できません。

  • INSERT ... ON DUPLICATE KEY UPDATE は、重複キーエラーが発生したときに、更新される行に共有ロックではなく、排他ネクストキーロックが配置されるという点で、単純な INSERT と異なります。

  • REPLACE は、一意のキーが競合していなければ、INSERT と同様に動作します。それ以外の場合は、置換される行に排他ネクストキーロックが配置されます。

  • INSERT INTO T SELECT ... FROM S WHERE ... は、T に挿入された各行に、ギャップロックなしの排他インデックスレコードロックを設定します。トランザクション分離レベルが READ COMMITTED である場合、または innodb_locks_unsafe_for_binlog が有効になっていて、トランザクション分離レベルが SERIALIZABLE でない場合、InnoDB は一貫性読み取り (ロックなし) として S 上で検索を実行します。それ以外の場合、InnoDBS から取得した行に共有ネクストキーロックを設定します。InnoDB は、後者の場合にロックを設定する必要があります。バックアップからのロールフォワードリカバリ時には、すべての SQL ステートメントを元とまったく同じ方法で実行する必要があります。

    CREATE TABLE ... SELECT ... は、INSERT ... SELECT の場合と同様に、SELECT を共有ネクストキーロックを使用して実行するか、一貫性読み取りとして実行します。

    構造文 REPLACE INTO t SELECT ... FROM s WHERE ... または UPDATE t ... WHERE col IN (SELECT ... FROM s ...)SELECT が使用されると、InnoDB はテーブル s の行に共有ネクストキーロックを設定します。

  • InnoDB は、テーブル上に事前に指定された AUTO_INCREMENT カラムの初期化中に、AUTO_INCREMENT カラムに関連付けられたインデックスの最後に排他ロックを設定します。InnoDB では、自動インクリメントカウンタにアクセスするときに、ロックがトランザクション全体の最後までではなく、現在の SQL ステートメントの最後まで続く、特別な AUTO-INC テーブルロックモードが使用されます。AUTO-INC テーブルロックが保持されている間は、ほかのセッションはそのテーブルに挿入できません。セクション14.2.2「InnoDB のトランザクションモデルおよびロック」を参照してください。

    InnoDB は、ロックを設定せずに、事前に初期化された AUTO_INCREMENT カラムの値をフェッチします。

  • FOREIGN KEY 制約がテーブル上で定義されている場合は、制約条件をチェックする必要がある挿入、更新、または削除が行われると、制約をチェックするために、参照されるレコード上に共有レコードレベルロックが設定されます。InnoDB は、制約が失敗する場合に備えて、これらのロックの設定も行います。

  • LOCK TABLES はテーブルロックを設定しますが、これらのロックを設定する InnoDB レイヤーよりも上位の MySQL レイヤーです。InnoDB は、innodb_table_locks = 1 (デフォルト) かつ autocommit = 0 の場合にテーブルロックを認識し、InnoDB よりも上位の MySQL レイヤーは、行レベルロックを識別します。

    それ以外の場合は、InnoDB の自動デッドロック検出では、このようなテーブルロックが関与するデッドロックを検出できません。また、この場合には上位の MySQL レイヤーは行レベルロックを識別しないため、現在別のセッションが行レベルロックを保持しているテーブル上でテーブルロックを取得できます。ただし、セクション14.2.10「デッドロックの検出とロールバック」で説明したように、これによりトランザクションの完全性が危険にさらされることはありません。セクション14.6.7「InnoDB テーブル上の制限」も参照してください。

14.2.9 暗黙的なトランザクションコミットとロールバック

MySQL は、デフォルトで新しい接続のセッション開始時に自動コミットモードが有効になります。そのため、各 SQL ステートメントからエラーが返されなかった場合に、MySQL はそのステートメントのあとでコミットを実行します。ステートメントからエラーが返された場合、コミットまたはロールバックの動作はそのエラーによって異なります。セクション14.19.4「InnoDB のエラー処理」を参照してください。

自動コミットが無効になっているセッションが、最後のトランザクションを明示的にコミットせずに終了した場合、MySQL はそのトランザクションをロールバックします。

一部のステートメントは、ユーザーがそのステートメントの実行前に COMMIT を実行した場合と同様に、暗黙的にトランザクションを終了します。詳細は、セクション13.3.3「暗黙的なコミットを発生させるステートメント」を参照してください。

14.2.10 デッドロックの検出とロールバック

InnoDB では、自動的にトランザクションのデッドロックが検出され、デッドロックを解除するためにトランザクション (複数の場合あり) がロールバックされます。InnoDB は、小さいトランザクションを選択してロールバックしようと試みます。トランザクションのサイズは、挿入、更新、または削除された行数によって決定されます。

InnoDB は、innodb_table_locks = 1 (デフォルト) かつ autocommit = 0 の場合にテーブルロックを認識し、それよりも上位の MySQL レイヤーは、行レベルロックを識別します。それ以外の場合、InnoDB は、MySQL LOCK TABLES ステートメントで設定されたテーブルロックまたは InnoDB 以外のストレージエンジンで設定されたロックが関連しているデッドロックを検出できません。このような状況を解決するには、innodb_lock_wait_timeout システム変数の値を設定します。

InnoDB でトランザクションの完全なロールバックが実行されると、トランザクションで設定されたすべてのロックが解放されます。ただし、エラーの結果として単一の SQL ステートメントのみがロールバックされると、ステートメントで設定された一部のロックが保持される可能性があります。これが発生する原因は、InnoDB では、どの行がどのステートメントで設定されたのかをあとで確認できないような形式で、行ロックが格納されるためです。

トランザクションで SELECT がストアドファンクションを呼び出し、そのファンクション内のステートメントに失敗した場合は、そのステートメントがロールバックされます。さらに、そのあとで ROLLBACK が実行された場合、トランザクション全体がロールバックされます。

デッドロックを回避するためにデータベース操作を編成する方法については、セクション14.2.11「デッドロックの対処方法」を参照してください。

14.2.11 デッドロックの対処方法

このセクションは、セクション14.2.10「デッドロックの検出とロールバック」に示したデッドロックに関する概念情報に基づいています。ここでは、デッドロックが最小限になるようにデータベース操作を編成する方法、およびアプリケーションで必要となる後続のエラー処理について説明します。

デッドロックは、トランザクションデータベースの古典的な問題ですが、特定のトランザクションをまったく実行できないほど発生頻度が高くなければ、危険ではありません。通常は、デッドロックが発生したためにトランザクションがロールバックされた場合に、それを再発行できる準備が常にできているようにアプリケーションを作成する必要があります。

InnoDB では自動行レベルロックが使用されます。単一の行を挿入または削除するだけのトランザクションの場合でも、デッドロックが発生する可能性があります。その原因は、これらの操作が実際には原子的でないためです。これらの操作では自動的に、挿入または削除される行のインデックスレコード (複数の可能性あり) にロックが設定されます。

次の方法を使用すれば、デッドロックに対処し、発生の可能性を減らすことができます。

  • いつでも、SHOW ENGINE INNODB STATUS コマンドを発行して、最近のデッドロックの原因を特定してください。これは、デッドロックが回避されるようにアプリケーションを調整する際に役立ちます。

  • 頻繁にデッドロックの警告が発生することに懸念がある場合は、innodb_print_all_deadlocks 構成オプションを有効にして、より広範囲にわたるデバッグ情報を収集してください。MySQL のエラーログには、最近のデッドロックだけでなく、各デッドロックに関する情報が記録されます。デバッグが完了したら、このオプションを無効にします。

  • デッドロックが原因でトランザクションに失敗した場合に、そのトランザクションを再発行できるように常に準備しておきます。デッドロックは危険ではありません。再度試してください。

  • トランザクションが競合する可能性を低くするために、トランザクションのサイズを小さく、期間を短く保ってください。

  • トランザクションが競合する可能性を低くするために、関連する一連の変更を行なった直後にトランザクションをコミットしてください。特に、コミットされていないトランザクションを含むインタラクティブな mysql セッションは、長時間開いたままにしないでください。

  • ロック読み取り (SELECT ... FOR UPDATE または SELECT ... LOCK IN SHARE MODE) を使用する場合は、READ COMMITTED などの低い分離レベルを使用してみてください。

  • トランザクション内の複数のテーブルを変更する場合や、同じテーブル内のさまざまな行のセットを変更する場合は、毎回、これらの操作を一貫性のある順序で実行してください。その結果、トランザクションで明示的に定義されたキューが生成され、デッドロックは発生しません。たとえば、さまざまな場所で同様の INSERTUPDATE、および DELETE ステートメントのシーケンスを複数回コーディングするのではなく、データベース操作をアプリケーション内の関数に編成したり、ストアドルーチンを呼び出したりします。

  • テーブルに適切なインデックスを追加してください。これにより、クエリーでスキャンする必要のあるインデックスレコード数が減少するため、ロックの設定も減少します。MySQL サーバーがクエリーに最適であるとみなすインデックスを特定するために、EXPLAIN SELECT を使用してください。

  • ロックの使用を減らしてください。古いスナップショットからのデータを返すために、SELECT を許可する余裕がある場合は、FOR UPDATE または LOCK IN SHARE MODE 句を追加しないでください。同じトランザクション内の各一貫性読み取りでは、独自の新しいスナップショットから読み取られるため、READ COMMITTED 分離レベルを使用することが適切な方法です。

  • ほかに方法がなければ、テーブルレベルロックを使用してトランザクションを直列化してください。InnoDB テーブルなどのトランザクションテーブルで LOCK TABLES を使用する正しい方法は、(START TRANSACTION ではなく) SET autocommit = 0 でトランザクションを開始し、そのあと LOCK TABLES を実行し、UNLOCK TABLES を呼び出す前にそのトランザクションを明示的にコミットすることです。たとえば、テーブル t1 に書き込み、テーブル t2 から読み取る必要がある場合は、次のように実行できます。

    SET autocommit=0;
    LOCK TABLES t1 WRITE, t2 READ, ...;... do something with tables t1 and t2 here ...COMMIT;
    UNLOCK TABLES;

    テーブルレベルロックを使用すると、テーブルへの並列更新が抑制されるため、デッドロックが回避されますが、負荷の高いシステムで応答性が低くなるという犠牲が伴います。

  • トランザクションを直列化する別の方法は、単一行だけを含む補助セマフォーテーブルを作成することです。ほかのテーブルにアクセスする前に、各トランザクションでその行を更新してください。これにより、すべてのトランザクションが直列方式で発生します。直列化ロックは行レベルロックであるため、この場合、InnoDB のインスタントデッドロック検出アルゴリズムも機能することに注意してください。MySQL のテーブルレベルロックを使用してデッドロックを解決するには、タイムアウト方式を使用する必要があります。

14.2.12 InnoDB マルチバージョン

InnoDBマルチバージョンストレージエンジンです。並列実行やロールバックなどのトランザクション機能をサポートするために、変更された行の古いバージョンに関する情報が保持されます。この情報は、テーブルスペース内にロールバックセグメントと呼ばれるデータ構造で (Oracle では類似したデータ構造のあとに) 格納されます。InnoDB では、トランザクションのロールバックで必要となる取り消し操作を実行するために、ロールバックセグメント内の情報が使用されます。また、この情報は、一貫性読み取りのために行の初期バージョンを構築する際にも使用されます。

マルチバージョン内部の詳細

InnoDB は内部的に、データベース内に格納された各行に 3 つのフィールドを追加します。6 バイトの DB_TRX_ID フィールドは、行を挿入または更新した最後のトランザクションに対して、トランザクション識別子を指示します。また、行内の特別ビットが削除されたとマークするように設定されている場合、削除は内部的に更新として処理されます。各行には、ロールポインタと呼ばれる 7 バイトの DB_ROLL_PTR フィールドも含まれています。ロールポインタは、ロールバックセグメントに書き込まれた Undo ログレコードを示しています。行が更新された場合は、Undo ログレコードに、更新される前の行の内容を再構築するために必要な情報が含まれます。6 バイトの DB_ROW_ID フィールドには、新しい行が挿入されると単調に増加する行 ID が含まれています。InnoDB によって自動生成されたクラスタ化されたインデックスには、行 ID 値が含まれます。それ以外の場合、インデックスに DB_ROW_ID カラムが含まれることはありません。

ロールバックセグメント内の Undo ログは、挿入および更新 Undo ログに分割されます。挿入 Undo ログはトランザクションロールバックでのみ必要であるため、トランザクションのコミット直後に破棄できます。更新 Undo ログも一貫性読み取りで使用されますが、InnoDB によってスナップショットが割り当てられたトランザクションが存在しなくなったあとでのみ破棄できます。更新 Undo ログ内のスナップショット情報は、データベース行の以前のバージョンを構築する際に一貫性読み取りで必要となる可能性があります。

ロールバックセグメントを管理するためのガイドライン

トランザクション (一貫性読み取りのみを発行するトランザクションを含む) を定期的にコミットしてください。それ以外の場合は、InnoDB は更新 Undo ログからデータを破棄できないため、ロールバックセグメントが大きくなり過ぎてテーブルスペースがいっぱいになる可能性があります。

一般に、ロールバックセグメント内の Undo ログレコードの物理的サイズは、それに対応する挿入された行や更新された行よりも小さいです。この情報を使用すると、ロールバックセグメントで必要となる領域を計算できます。

InnoDB マルチバージョンスキームでは、SQL ステートメントで行を削除しても、その行はすぐにデータベースから物理的に削除されません。InnoDB は、削除用に書き込まれた更新 Undo ログレコードが破棄されたときにのみ、対応する行およびそのインデックスレコードを物理的に削除します。このような削除操作はパージと呼ばれ、非常に高速です。通常は、削除が行われなかった SQL ステートメントと同じ時系列順で実行されます。

テーブル内で小さめのバッチの行をほぼ同じ速度で挿入および削除すると、すべてのデッド行が原因で、パージスレッドが遅延し始め、増加し続ける可能性があります。これにより、すべてにおいてディスクが抑制され、非常に低速になります。このような場合は、新たな行操作を抑制し、innodb_max_purge_lag システム変数を調整することで、より多くのリソースをパージスレッドに割り当てます。詳細は、セクション14.12「InnoDB の起動オプションおよびシステム変数」を参照してください。

14.2.13 InnoDB テーブルおよびインデックスの構造

このセクションでは、InnoDB のテーブル、インデックス、およびこれらに関連付けられたメタデータを物理レベルで表示する方法について説明します。この情報は、主にパフォーマンスチューニングおよびトラブルシューティングに役立ちます。

14.2.13.1 InnoDB テーブル用の .frm ファイルの役割

MySQL では、データベースディレクトリ内の .frm ファイルに、テーブルに関するそのデータディクショナリ情報が格納されます。その他の MySQL ストレージエンジンとは異なり、InnoDB では、テーブルスペース内にある独自の内部データディクショナリのテーブルに関する情報のエンコードも行われます。MySQL でテーブルまたはデータベースが削除されると、1 つ以上の .frm ファイルおよび InnoDB データディクショナリ内の対応するエントリも削除されます。単に .frm ファイルを移動するだけでは、データベース間で InnoDB テーブルを移動できません。

14.2.13.2 クラスタインデックスとセカンダリインデックス

すべての InnoDB テーブルは、行のデータが格納されているクラスタ化されたインデックスと呼ばれる特別なインデックスを持っています。一般に、クラスタ化されたインデックスは主キーのシノニムです。クエリー、挿入、およびその他のデータベース操作で最適なパフォーマンスを実現するには、InnoDB がクラスタ化されたインデックスを使用して、テーブルごとにもっとも一般的な検索と DML 操作を最適化する方法について理解する必要があります。

  • テーブル上で PRIMARY KEY を定義すると、InnoDB ではそれがクラスタ化されたインデックスとして使用されます。作成するテーブルごとに主キーを定義します。論理的に一意で、Null 以外のカラムまたはカラムのセットが存在しない場合は、自動的に値が入力される新しい自動インクリメントカラムを追加します。

  • テーブルに PRIMARY KEY が定義されていない場合、MySQL はすべてのキーカラムが NOT NULLUNIQUE インデックスを最初に検索し、InnoDB はそれをクラスタ化されたインデックスとして使用します。

  • テーブルに PRIMARY KEY も適切な UNIQUE インデックスも存在しない場合には、InnoDB の内部で、行 ID 値を含む合成カラム上に非表示のクラスタ化されたインデックスが生成されます。そのようなテーブルでは、InnoDB が行に割り当てる ID に基づいて行の順序付けが行われます。行 ID は、新しい行が挿入されると単調に増加する 6 バイトのフィールドです。したがって、行 ID で順序付けられた行が物理的な挿入順になります。

クラスタ化されたインデックスでクエリーを高速にする方法

クラスタ化されたインデックスから行にアクセスすると、インデックス検索がすべての行データを持つページで直接実行されるため、高速になります。多くの場合、テーブルのサイズが大きい場合にクラスタ化されたインデックスアーキテクチャーを使用すれば、インデックスレコードとは別のページに行データを格納するストレージ編成と比べて、ディスク I/O 操作を節約できます。(たとえば MyISAM では、データ行に使用されるファイルとインデックスレコードに使用されるファイルは異なります。)

セカンダリインデックスとクラスタ化されたインデックスとの関係

クラスタ化されたインデックス以外のインデックスは、すべてセカンダリインデックスと呼ばれます。InnoDB では、セカンダリインデックス内の各レコードに、行の主キーカラム、およびセカンダリインデックスに指定されたカラムが含まれます。InnoDB では、クラスタ化されたインデックス内で行を検索する際に、この主キー値が使用されます。

主キーが長くなると、セカンダリインデックスで使用される領域も多くなるため、主キーは短い方が利点があります。

InnoDB のクラスタインデックスおよびセカンダリインデックスの利点を得るためのコーディングのガイドラインについては、セクション8.3.2「主キーの使用」セクション8.3「最適化とインデックス」セクション8.5「InnoDB テーブルの最適化」セクション8.3.2「主キーの使用」を参照してください。

14.2.13.3 FULLTEXT インデックス

テキストベースのカラム (CHARVARCHAR、または TEXT カラム) 上に作成されたインデックスのタイプです。これを使用すると、ストップワードとして定義されている任意の単語が省略されることで、これらのカラム内に含まれるデータ上での InnoDB のクエリーおよび DML 操作の速度を上げる際に役立ちます。

FULLTEXT インデックスは、CREATE TABLE ステートメントの一部として定義することも、あとで ALTER TABLE または CREATE INDEX を使用して追加することもできます。

全文検索は、MATCH() ... AGAINST 構文を使用して実行されます。使用法については、セクション12.9「全文検索関数」を参照してください。

全文インデックスの設計

InnoDBFULLTEXT インデックスでは、転置インデックスの設計が使用されています。転置インデックスには、単語のリスト、および単語ごとに、その単語が出現するドキュメントのリストが格納されます。近接検索をサポートするために、単語ごとの位置情報もバイトオフセットとして格納されます。

全文インデックステーブル

次の例に示すように、InnoDBFULLTEXT インデックスごとに、インデックステーブルのセットが作成されます。

CREATE TABLE opening_lines (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
opening_line TEXT(500),
author VARCHAR(200),
title VARCHAR(200),
FULLTEXT idx (opening_line)
) ENGINE=InnoDB;
mysql> SELECT table_id, name, space from INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE name LIKE 'test/%';
+----------+----------------------------------------------------+-------+
| table_id | name | space |
+----------+----------------------------------------------------+-------+
| 333 | test/FTS_0000000000000147_00000000000001c9_INDEX_1 | 289 |
| 334 | test/FTS_0000000000000147_00000000000001c9_INDEX_2 | 290 |
| 335 | test/FTS_0000000000000147_00000000000001c9_INDEX_3 | 291 |
| 336 | test/FTS_0000000000000147_00000000000001c9_INDEX_4 | 292 |
| 337 | test/FTS_0000000000000147_00000000000001c9_INDEX_5 | 293 |
| 338 | test/FTS_0000000000000147_00000000000001c9_INDEX_6 | 294 |
| 330 | test/FTS_0000000000000147_BEING_DELETED | 286 |
| 331 | test/FTS_0000000000000147_BEING_DELETED_CACHE | 287 |
| 332 | test/FTS_0000000000000147_CONFIG | 288 |
| 328 | test/FTS_0000000000000147_DELETED | 284 |
| 329 | test/FTS_0000000000000147_DELETED_CACHE | 285 |
| 327 | test/opening_lines | 283 |
+----------+----------------------------------------------------+-------+
12 rows in set (0.02 sec) 

最初の 6 つのテーブルは転置インデックスを表し、近接検索インデックステーブルと呼ばれます。受信ドキュメントがトークン化されると、各単語が位置情報およびドキュメント ID (DOC_ID) とともに、インデックステーブルに挿入されます。単語は完全にソートされてから、単語の最初の文字の文字セット重みに基づいて、6 つのインデックステーブル間でパーティション化されます。

転置インデックスは、インデックスの並列作成をサポートするために、6 つの補助インデックステーブルにパーティション化されます。デフォルトでは、2 つのスレッドを使用して、単語および関連するデータのトークン化、ソート、およびインデックステーブルへの挿入が実行されます。スレッドの数は、innodb_ft_sort_pll_degree オプションを使用することで構成可能です。大きなテーブル上に FULLTEXT インデックスを作成する際には、スレッドの数を多くすることを検討してください。

補助インデックステーブル名の前には FTS_、後ろには INDEX_* が付けられます。各インデックステーブルは、インデックス付きのテーブルの table_id と一致するインデックステーブル名に含まれる 16 進値によって、インデックス付きのテーブルに関連付けられます。たとえば、test/opening_lines テーブルの table_id327 (16 進値は 0x147) です。前述の例で示したように、16 進値の 147 は、test/opening_lines テーブルに関連付けられたインデックステーブルの名前に表示されます。

補助インデックス名に表示されるもう 1 つの 16 進値は、FULLTEXT インデックスの index_id です。たとえば、補助テーブル名 test/FTS_0000000000000147_00000000000001c9_INDEX_1 では、16 進値 1c9 の 10 進値は 457 です。opening_lines テーブルで定義されたインデックス (idx) は、INFORMATION_SCHEMA.INNODB_SYS_INDEXES テーブルでこの値 (457) に対してクエリーを実行することで識別できます。

mysql> SELECT index_id, name, table_id, space from INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE index_id=457;
+----------+------+----------+-------+
| index_id | name | table_id | space |
+----------+------+----------+-------+
| 457 | idx | 327 | 283 |
+----------+------+----------+-------+
1 row in set (0.00 sec) 

innodb_file_per_table を有効にすると、インデックステーブルが独自のテーブルスペースに格納されます。innodb_file_per_table を無効にすると、インデックステーブルが InnoDB のシステムテーブルスペース (スペース 0) に格納されます。

注記

MySQL 5.6.5 で導入されたバグが原因で、innodb_file_per_table を有効にしても、インデックステーブルは InnoDB のシステムテーブルスペース (スペース 0) に作成されます。このバグは、MySQL 5.6.20 および MySQL 5.7.5 で修正されました (Bug#18635485)。

前述の例で示したその他のインデックステーブルは、FULLTEXT インデックスの削除処理および内部状態の格納で使用されます。

  • FTS_*_DELETED および FTS_*_DELETED_CACHE: 削除されるが、データはまだ全文インデックスから削除されないドキュメントのドキュメント ID (DOC_ID) が含まれます。FTS_*_DELETED_CACHE は、FTS_*_DELETED テーブルのインメモリーバージョンです。

  • FTS_*_BEING_DELETED および FTS_*_BEING_DELETED_CACHE: 削除され、現在データが全文インデックスから削除中であるドキュメントのドキュメント ID (DOC_ID) が含まれます。FTS_*_BEING_DELETED_CACHE テーブルは、FTS_*_BEING_DELETED テーブルのインメモリーバージョンです。

  • FTS_*_CONFIG: FULLTEXT インデックスの内部状態に関する情報が格納されます。もっとも重要な点は、解析され、ディスクにフラッシュされたドキュメントを識別する FTS_SYNCED_DOC_ID が格納されることです。クラッシュリカバリの場合、ドキュメントを再解析し、FULLTEXT インデックスキャッシュに追加し直すことができるように、ディスクにフラッシュされていないドキュメントを識別する際に、FTS_SYNCED_DOC_ID 値が使用されます。このテーブル内のデータを表示するには、INFORMATION_SCHEMA.INNODB_FT_CONFIG テーブルでクエリーを実行します。

全文インデックスキャッシュ

ドキュメントが挿入されると、トークン化され、各単語および関連付けられたデータが FULLTEXT インデックスに挿入されます。このプロセスが実行されると、小さなドキュメントの場合でも、補助インデックステーブルへの多数の小規模な挿入が発生します。これにより、競合の発生時に、これらのテーブルへの並列アクセスが発生する可能性があります。この問題を回避するために、InnoDB では、最近挿入された行に対するインデックステーブルの挿入を一時的にキャッシュに入れるために、FULLTEXT インデックスキャッシュが使用されます。このインメモリーキャッシュの構造では、キャッシュがいっぱいになるまで挿入が保持され、そのあと、ディスク (補助インデックステーブル) にバッチフラッシュされます。INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE テーブルでクエリーを実行すると、最近挿入された行のトークン化されたデータを表示できます。

キャッシュおよびバッチフラッシュの動作によって、補助インデックステーブルへの頻繁な更新が回避されますが、負荷の高い挿入時および更新時に並列アクセスの問題が発生する可能性があります。また、バッチ技術を使用すると、同じ単語への挿入が複数回発生することも回避され、重複エントリも最小限になります。各単語を個別にフラッシュする代わりに、同じ単語の挿入がマージされ、単一のエントリとしてディスクにフラッシュされるため、補助インデックステーブルのサイズをできるかぎり小さく保ちながら、挿入の効率性が改善されます。

全文インデックスキャッシュのサイズを (テーブルごとに) 構成するには、innodb_ft_cache_size 変数が使用されます。これにより、全文インデックスキャッシュがフラッシュされる頻度が影響を受けます。特定のインスタンスで innodb_ft_total_cache_size オプションを使用すれば、すべてのテーブルに対応したグローバルな全文インデックスキャッシュのサイズ制限を定義することもできます。

全文インデックスキャッシュには、補助インデックステーブルと同じ情報が格納されます。ただし、全文インデックスキャッシュでは、最近挿入された行のトークン化されたデータのみがキャッシュに入れられます。すでにディスク (全文補助テーブル) にフラッシュされているデータは、クエリー時に全文インデックスキャッシュに戻りません。補助インデックステーブル内のデータは、直接クエリーが実行されます。補助インデックステーブルからの結果は、全文インデックスキャッシュからの結果とマージされてから返されます。

InnoDB の全文ドキュメント ID および FTS_DOC_ID カラム

InnoDB では、全文インデックス内の単語をその単語が出現するドキュメントレコードとマップする際に、ドキュメント ID (DOC_ID) と呼ばれる一意のドキュメント識別子が使用されます。このマッピングには、インデックス付きテーブル上の FTS_DOC_ID カラムが必要です。FTS_DOC_ID カラムが定義されていない場合は、全文インデックスの作成時に、InnoDB によって自動的に非表示の FTS_DOC_ID カラムが追加されます。次の例で、この動作を実演します。

次のテーブル定義には、FTS_DOC_ID カラムが含まれていません。

CREATE TABLE opening_lines (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
opening_line TEXT(500),
author VARCHAR(200),
title VARCHAR(200)
) ENGINE=InnoDB; 

CREATE FULLTEXT INDEX 構文を使用して、テーブル上に全文インデックスを作成すると、FTS_DOC_ID カラムが追加されるように InnoDB がテーブルを再構築してしていることをレポートする警告が返されます。

mysql> CREATE FULLTEXT INDEX idx ON opening_lines(opening_line);
Query OK, 0 rows affected, 1 warning (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------+
| Warning | 124 | InnoDB rebuilding table to add column FTS_DOC_ID |
+---------+------+--------------------------------------------------+
1 row in set (0.00 sec) 

ALTER TABLE を使用して、FTS_DOC_ID カラムが存在しないテーブルに全文インデックスを追加するときにも、同じ警告が返されます。CREATE TABLE の実行時に全文インデックスを作成する場合に、FTS_DOC_ID カラムを定義しないと、InnoDB によって警告なしで、非表示の FTS_DOC_ID カラムが追加されます。

CREATE TABLE の実行時に FTS_DOC_ID カラムを定義するには、すでにデータがロードされているテーブル上に全文インデックスを作成する必要があります。データをロードする前に、テーブル上に FTS_DOC_ID カラムが定義されている場合は、新しいカラムが追加されるようにテーブルおよびそのインデックスを再構築する必要がありません。CREATE FULLTEXT INDEX のパフォーマンスに関心がない場合は、InnoDB で自動的に作成されるように、FTS_DOC_ID カラムを除外します。InnoDB によって、FTS_DOC_ID_INDEX という名前の FTS_DOC_ID カラム上に、一意のインデックスとともに非表示の FTS_DOC_ID が作成されます。独自の FTS_DOC_ID カラムを作成する場合は、次の例で示すように、カラムを BIGINT UNSIGNED NOT NULL として定義し、FTS_DOC_ID (すべて大文字) という名前を付けます。

注記

AUTO_INCREMENT として FTS_DOC_ID カラムを定義する必要がありませんが、AUTO_INCREMENT を使用した方が簡単にデータをロードできます。

CREATE TABLE opening_lines (
FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
opening_line TEXT(500),
author VARCHAR(200),
title VARCHAR(200)
) ENGINE=InnoDB; 

FTS_DOC_ID カラムをユーザー自身で定義するように決定した場合は、空の値や重複する値が回避されるようにカラムを管理することがユーザーの責任となります。FTS_DOC_ID 値は再使用できません。つまり、FTS_DOC_ID 値は増加し続けます。

オプションで、FTS_DOC_ID カラム上に必要な一意の FTS_DOC_ID_INDEX (すべて大文字) を作成することもできます。

CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on opening_lines(FTS_DOC_ID);

FTS_DOC_ID_INDEX を作成しない場合は、InnoDB によって自動的に作成されます。

InnoDB による全文インデックスの削除処理

全文インデックスカラムが含まれるレコードを削除すると、補助インデックステーブルへの多数の小規模な削除が発生します。これにより、競合の発生時に、これらのテーブルへの並列アクセスが発生する可能性があります。この問題を回避するために、インデックス付きのテーブルからレコードが削除されるたびに、削除されたドキュメントのドキュメント ID (DOC_ID) が特別な DELETED テーブルに記録され、インデックス付きのレコードが全文インデックスに残ります。クエリーの結果が返される前に、DELETED テーブル内の情報を使用して、削除されたドキュメント ID が取り除かれます。この設計の利点は、削除が高速で、低負荷であることです。欠点は、レコードの削除後に、すぐにインデックスのサイズが削減されないことです。削除したエントリの全文インデックスエントリを削除するには、innodb_optimize_fulltext_only=ON を使用してインデックス付きのテーブル上で OPTIMIZE TABLE を実行して、全文インデックスを再構築します。詳細は、InnoDB 全文インデックスの最適化を参照してください。

InnoDB による全文インデックスのトランザクション処理

InnoDBFULLTEXT インデックスには、そのキャッシュおよびバッチ処理の動作のために、特別なトランザクション処理の特性が備わっています。特に、FULLTEXT インデックス上の更新および挿入は、トランザクションのコミット時に処理されます。つまり、FULLTEXT 検索では、コミットされたデータのみを表示できます。次の例で、この動作を実演します。FULLTEXT 検索では、挿入された行がコミットされたあとにはじめて、結果が返されます。

mysql> CREATE TABLE opening_lines (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
opening_line TEXT(500),
author VARCHAR(200),
title VARCHAR(200),
FULLTEXT idx (opening_line)
) ENGINE=InnoDB;
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO opening_lines(opening_line,author,title) VALUES
('Call me Ishmael.','Herman Melville','Moby-Dick'),
('A screaming comes across the sky.','Thomas Pynchon','Gravity\'s Rainbow'),
('I am an invisible man.','Ralph Ellison','Invisible Man'),
('Where now? Who now? When now?','Samuel Beckett','The Unnamable'),
('It was love at first sight.','Joseph Heller','Catch-22'),
('All this happened, more or less.','Kurt Vonnegut','Slaughterhouse-Five'),
('Mrs. Dalloway said she would buy the flowers herself.','Virginia Woolf','Mrs. Dalloway'),
('It was a pleasure to burn.','Ray Bradbury','Fahrenheit 451');
Query OK, 8 rows affected (0.00 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line) AGAINST('Ishmael');
+----------+
| COUNT(*) |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line) AGAINST('Ishmael');
+----------+
| COUNT(*) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec) 
InnoDB による全文インデックスのモニター

次の INFORMATION_SCHEMA テーブルでクエリーを実行すると、InnoDBFULLTEXT インデックスの特別なテキスト処理の側面をモニターおよび調査できます。

  • INNODB_FT_CONFIG

  • INNODB_FT_INDEX_TABLE

  • INNODB_FT_INDEX_CACHE

  • INNODB_FT_DEFAULT_STOPWORD

  • INNODB_FT_DELETED

  • INNODB_FT_BEING_DELETED

INNODB_SYS_INDEXES および INNODB_SYS_TABLES でクエリーを実行すると、FULLTEXT インデックスおよびテーブルに関する基本情報を表示することもできます。

これらのテーブルについての詳細は、INFORMATION_SCHEMA のドキュメントを参照してください。

14.2.13.4 InnoDB インデックスの物理構造

すべての InnoDB インデックスは、インデックスレコードがツリーのリーフページ内に格納される B ツリーです。インデックスページのデフォルトサイズは 16K バイトです。新しいレコードが挿入されると、InnoDB はページの 1/16 を、将来のインデックスレコードの挿入や更新に備えて空けようとします。

インデックスレコードが順次 (昇順または降順) に挿入されると、インデックスページの約 15/16 までがいっぱいになります。レコードがランダムに挿入された場合は、ページの 1/2 から 15/16 までがいっぱいになります。インデックスページのフィルファクタが 1/2 を下回ると、InnoDB はページを解放するために、インデックスツリーを縮小しようとします。

注記

インスタンスを作成する前に、innodb_page_size 構成オプションを設定すると、MySQL インスタンス内のすべての InnoDB テーブルスペースのページサイズを指定できます。一度 MySQL インスタンスのページサイズが設定されたら、変更できません。サポートされるサイズは、オプションの値 16k8k、および 4k に対応する 16K バイト、8K バイト、および 4K バイトです。

特定の InnoDB ページサイズを使用している MySQL インスタンスは、別のページサイズを使用するインスタンスのデータファイルやログファイルを使用できません。

14.2.13.5 挿入バッファー

多くの場合、データベースアプリケーションでは、新しい行が主キーの昇順で挿入されます。この場合、クラスタ化されたインデックスの順序が主キーと同じであるというレイアウトのために、InnoDB テーブルへの挿入時に、ディスクからのランダムな読み取りが必要ありません。

その一方で、通常、セカンダリインデックスは一意ではなく、セカンダリインデックスへの挿入は比較的ランダムな順序で発生します。同様に、削除および更新によって、セカンダリインデックス内の隣接しないデータページが影響を受ける可能性があります。このため、InnoDB で特別なメカニズムが使用されることなく、多数のランダムなディスク I/O が発生します。

インデックスレコードを挿入したり、削除対象のマークを付けたり、一意でないセカンダリインデックスから削除したりすると、InnoDB によって、セカンダリインデックスがバッファープール内に存在するかどうかがチェックされます。これに該当する場合は、InnoDB によって変更が直接インデックスページに適用されます。バッファープール内にインデックスページが見つからない場合は、InnoDB によって、挿入バッファーと呼ばれる特別な構造に変更が記録されます。挿入バッファーは、バッファープール内に完全に収容されるようにサイズが小さく保たれるため、変更を非常にすばやく適用できます。このプロセスは、変更バッファーと呼ばれます。(以前は、挿入にのみ適用されていたため、挿入バッファーと呼ばれていました。データ構造は、引き続き挿入バッファーと呼ばれています。)

挿入バッファーをフラッシュするためのディスク I/O

挿入バッファーは、データベース内のセカンダリインデックスツリーに定期的にマージされます。多くの場合は、複数の変更をインデックスツリーの同じページにマージできるため、ディスク I/O 操作を節約できます。挿入バッファーによって、テーブルへの挿入速度が最大 15 倍に上昇すると測定されています。

挿入バッファーのマージは、トランザクションがコミットされたあとに、発生し続ける可能性があります。実際、これはサーバーがシャットダウンし、再起動したあとまで発生し続ける可能性があります (セクション14.19.2「InnoDB のリカバリの強制的な実行」を参照してください)。

多くのセカンダリインデックスが更新される必要があり、多くの行が挿入されたときは、挿入バッファーのマージに何時間もかかる可能性があります。この期間は、ディスク I/O が増加します。これにより、ディスクに負荷がかかるクエリーは大幅に低速になります。もう 1 つの重要なバックグラウンド I/O 操作は、パージスレッドです (セクション14.2.12「InnoDB マルチバージョン」を参照してください)。

14.2.13.6 適応型ハッシュインデックス

適応型ハッシュインデックス (AHI) と呼ばれる機能を使用すると、トランザクションの機能や信頼性を犠牲にせずに、バッファープールのワークロードと十分なメモリーが適切に組み合わされたシステム上でインメモリーデータベースと同様に InnoDB を実行できます。この機能はサーバーの起動時に、innodb_adaptive_hash_index オプションを使用すると有効になり、--skip-innodb_adaptive_hash_index を使用すると無効になります。

監視対象の検索パターンに基づいて、MySQL はインデックスキーのプリフィクスを使用して、ハッシュインデックスを構築します。キーのプリフィクスは任意の長さにすることができますが、ハッシュインデックスには B ツリー内の値の一部しか表示されない可能性があります。ハッシュインデックスは、頻繁にアクセスされるインデックスのページに対する要求に応じて構築されます。

テーブルがメインメモリー内にほぼ完全に収容されている場合は、任意の要素の直接検索を有効にし、インデックス値をポインタの一種に変換すると、ハッシュインデックスを使用してクエリーを高速にすることができます。InnoDB には、インデックスの検索をモニターするメカニズムが備わっています。ハッシュインデックスの構築がクエリーにとって有益であると InnoDB が判断した場合は、自動的にそのインデックスが構築されます。

一部のワークロードでは、ハッシュインデックスの検索による高速化の方が、インデックスの検索をモニターしたり、ハッシュインデックスの構造を保持したりする追加の作業よりも重要です。複数の並列結合などの負荷の高いワークロードでは、適応型ハッシュインデックスへのアクセスを保護する読み取り/書き込みロックが競合の原因となる可能性があります。LIKE 演算子と % ワイルドカードを使用したクエリーも、AHI を使用する利点が得られない傾向があります。適応型ハッシュインデックスが必要のないワークロードでは、これをオフにすれば、不要なパフォーマンスのオーバーヘッドが削減されます。この機能が特定のシステムに適しているかどうかを事前に予測することは困難であるため、現実的なワークロードを使用して、有効にした場合と無効にした場合の両方でベンチマークを実行することを検討してください。MySQL 5.6 以上ではアーキテクチャーが変更され、以前のリリースよりも、適応型ハッシュインデックスを無効にすることに適したワークロードが多くなりました。ただし、デフォルトでは引き続き有効になっています。

常に、ハッシュインデックスはテーブル上の既存の B ツリーインデックスに基づいて構築されます。InnoDB は、B ツリーインデックスに対して InnoDB が検出した検索パターンに応じて、任意の長さの B ツリーに定義されたキーのプリフィクスに、ハッシュインデックスを構築できます。ハッシュインデックスは、頻繁にアクセスされるインデックスのページのみが対象となるように、部分的に構築できます。

適応型ハッシュインデックスの使用、およびこれを SHOW ENGINE INNODB STATUS コマンドの出力の SEMAPHORES セクションで使用した場合の競合をモニターできます。btr0sea.c で作成された RW ラッチ上で待機しているスレッドが多く見られる場合は、適応型ハッシュインデックスを無効にすると役立つ可能性があります。

ハッシュインデックスのパフォーマンス特性についての詳細は、セクション8.3.8「B ツリーインデックスとハッシュインデックスの比較」を参照してください。

14.2.13.7 物理的な行構造

InnoDB テーブルの物理的な行構造は、テーブル作成時に指定された行フォーマットによって異なります。InnoDB のデフォルトでは、Antelope ファイル形式とその COMPACT 行フォーマットが使用されます。REDUNDANT 形式は、古い MySQL バージョンとの互換性を保つために使用可能です。セクション14.9「InnoDB の行ストレージと行フォーマット」およびセクション14.7「InnoDB 圧縮テーブル」で説明するように、innodb_file_per_table 設定を有効にすると、新しい Barracuda ファイル形式を DYNAMIC および COMPRESSED 行フォーマットとともに使用することもできます。

InnoDB テーブルの行フォーマットをチェックするには、SHOW TABLE STATUS を使用します。例:

mysql> SHOW TABLE STATUS IN test1\G
*************************** 1. row *************************** Name: t1 Engine: InnoDB Version: 10 Row_format: Compact Rows: 0 Avg_row_length: 0 Data_length: 16384
Max_data_length: 0 Index_length: 16384 Data_free: 0 Auto_increment: 1 Create_time: 2014-10-31 16:02:01 Update_time: NULL Check_time: NULL Collation: latin1_swedish_ci Checksum: NULL Create_options: Comment:
1 row in set (0.00 sec)

INFORMATION_SCHEMA.INNODB_SYS_TABLES でクエリーを実行することで、InnoDB テーブルの行フォーマットをチェックすることもできます。

mysql> SELECT NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test1/t1';
+----------+------------+
| NAME | ROW_FORMAT |
+----------+------------+
| test1/t1 | Compact |
+----------+------------+

COMPACT 行フォーマットを使用すると、行のストレージ領域が約 20% 減少しますが、一部の操作では CPU 使用率が高くなります。ワークロードが、キャッシュヒット率とディスク速度によって制限される通常のワークロードであれば、COMPACT 形式が高速になる可能性があります。ワークロードが CPU 速度によって制限されるまれなケースでは、COMPACT 形式が低速になる可能性があります。

REDUNDANT 行フォーマットを使用する InnoDB テーブル内の行には、次のような特性があります。

  • 各インデックスレコードには、6 バイトのヘッダーが含まれています。このヘッダーは、連続するレコードをリンクするために使用されます。また、行レベルロックでも使用されます。

  • クラスタ化されたインデックス内のレコードには、すべてのユーザー定義カラムのフィールドが含まれます。さらに、6 バイトのトランザクション ID フィールドと 7 バイトのロールポインタフィールドも含まれています。

  • テーブルに主キーが定義されなかった場合は、各クラスタ化されたインデックスレコードに 6 バイトの行 ID フィールドも含まれています。

  • 各セカンダリインデックスレコードには、セカンダリインデックス内に存在しないクラスタ化されたインデックスキーに定義されたすべての主キーフィールドも含まれています。

  • レコードには、そのレコードの各フィールドへのポインタが含まれます。レコード内のフィールド長の合計が 128 バイト未満の場合はポインタが 1 バイト、128 バイト以上の場合はポインタが 2 バイトになります。これらのポインタの配列はレコードディレクトリと呼ばれます。これらのポインタが示す領域は、レコードのデータ部分と呼ばれます。

  • InnoDB には内部的に、固定長形式の CHAR(10) などの固定長文字カラムが格納されます。InnoDB は、VARCHAR カラム内の末尾の空白を切り捨てません。

  • SQL の NULL 値では、レコードディレクトリに 1 バイトまたは 2 バイトが予約されます。それ以外に、SQL の NULL 値では、可変長カラム内に格納されるとレコードのデータ部分にゼロバイトが予約されます。固定長カラムでは、レコードのデータ部分内にカラムの固定長が予約されます。NULL 値用に固定領域を予約すると、インデックスページの断片化が発生せずに、カラムを NULL から非 NULL 値に更新できます。

COMPACT 行フォーマットを使用する InnoDB テーブル内の行には、次のような特性があります。

  • 各インデックスレコードには、前に可変長ヘッダーが付く可能性のある 5 バイトのヘッダーが含まれています。このヘッダーは、連続するレコードをリンクするために使用されます。また、行レベルロックでも使用されます。

  • レコードヘッダーの可変長部分には、NULL カラムを示すビットベクトルが含まれています。NULL にすることができるインデックス内のカラム数が N である場合は、ビットベクトルで CEILING(N/8) バイトが占有されます。(たとえば、NULL にすることができるカラムが 9 から 15 までの任意の数だけ存在する場合は、ビットベクトルで 2 バイトが使用されます。)このベクトル内のビット以外の領域は、NULL のカラムで占有されません。ヘッダーの可変長部分には、可変長カラムの長さも含まれています。各長さは、カラムの最大長に応じて、1 バイトと 2 バイトのいずれかになります。インデックス内のすべてのカラムが NOT NULL でかつ固定長である場合、レコードヘッダーには可変長部分が含まれません。

  • NULL 可変長フィールドごとに、レコードヘッダーに 1 バイトまたは 2 バイトのカラム長が含まれます。カラムの一部が外部のオーバーフローページに格納される場合や、最大長が 255 バイトを超え、実際の長さが 127 バイトを超える場合にのみ、2 バイトが必要になります。カラムが外部に格納された場合、2 バイトの長さは、内部に格納された部分の長さに、外部に格納された部分への 20 バイトのポインタを加えた長さを示します。内部の部分は 768 バイトであるため、長さは 768+20 になります。20 バイトのポインタには、そのカラムの実際の長さが格納されます。

  • レコードヘッダーのあとに、非 NULL カラムのデータ内容が続きます。

  • クラスタ化されたインデックス内のレコードには、すべてのユーザー定義カラムのフィールドが含まれます。さらに、6 バイトのトランザクション ID フィールドと 7 バイトのロールポインタフィールドも含まれています。

  • テーブルに主キーが定義されなかった場合は、各クラスタ化されたインデックスレコードに 6 バイトの行 ID フィールドも含まれています。

  • 各セカンダリインデックスレコードには、セカンダリインデックス内に存在しないクラスタ化されたインデックスキーに定義されたすべての主キーフィールドも含まれています。これらの主キーフィールドのいずれかが可変長である場合、各セカンダリインデックスのレコードヘッダーには、そのセカンダリインデックスが固定長カラムで定義されている場合でも、それらのフィールドの長さを記録するための可変長部分が含まれます。

  • InnoDB には内部的に、固定長形式の CHAR(10) などの固定長で固定幅の文字カラムが格納されます。InnoDB は、VARCHAR カラム内の末尾の空白を切り捨てません。

  • InnoDB は、後続領域を切り取ることで内部的に UTF-8 CHAR(N) カラムを N バイトで格納しようとします。(REDUNDANT 行フォーマットでは、このようなカラムで 3 × N バイトが占有されます。)多くの場合は、最小領域 N を予約すると、インデックスページの断片化が発生せずに、カラムの更新を正常に実行できます。

14.3 InnoDB の構成

InnoDB 構成について最初に決定することは、InnoDB データファイルのレイアウト方法、および InnoDB ストレージエンジン用に割り当てるメモリーの量です。これらの選択を記録するには、起動時に MySQL で読み取られる構成ファイル内に記録するか、または起動スクリプトのコマンド行オプションとして指定します。オプション、説明、および許可されるパラメータ値の完全なリストについては、セクション14.12「InnoDB の起動オプションおよびシステム変数」を参照してください。

InnoDB テーブルスペースおよびログファイルの概要

InnoDB ストレージエンジンで管理されている 2 つの重要なディスクベースのリソースは、そのテーブルスペースデータファイルとログファイルです。InnoDB 構成オプションを指定しない場合は、MySQL によって MySQL データディレクトリ内に、わずかに 12M バイトよりも大きい ibdata1 という名前の自動拡張データファイルと、ib_logfile0 および ib_logfile1 という名前の 2 つのログファイルが作成されます。これらのサイズは、innodb_log_file_size システム変数のサイズで指定されます。適切なパフォーマンスを実現するには、次の例で説明するように、InnoDB パラメータを明示的に指定します。当然、ハードウェアおよび要件に合うように設定を編集します。

ここで示す例は代表的なものです。InnoDB に関連する構成パラメータに関する追加情報については、セクション14.12「InnoDB の起動オプションおよびシステム変数」を参照してください。

ストレージデバイスに関する考慮事項

場合によっては、一部のデータが同じ物理ディスク上に配置されてない場合に、データベースのパフォーマンスが改善されることがあります。非常に多くの場合、ログファイルをデータとは別のディスク上に配置すると、パフォーマンスの改善に役立ちます。次の例で、この方法を示します。2 つのデータファイルが別々のディスク上に配置され、ログファイルが 3 台目のディスク上に配置されています。InnoDB では、1 番目のデータファイルから順番にテーブルスペースに収容されます。InnoDB データファイルとして、RAW ディスクパーティション (RAW デバイス) を使用することもできます。これにより、I/O の速度が上がる可能性があります。セクション14.5.8「共有テーブルスペースでの RAW ディスクパーティションの使用」を参照してください。

注意

InnoDB はトランザクションセーフな (ACID に準拠した) MySQL 用のストレージエンジンであり、ユーザーデータを保護するためのコミット、ロールバック、およびクラッシュリカバリ機能を備えています。ただし、ベースとなるオペレーティングシステムやハードウェアが公表どおりに機能しない場合は、実行できません。多くのオペレーティングシステムやディスクサブシステムでは、パフォーマンスを改善するために書き込み操作が遅延したり、再指示されたりする可能性があります。一部のオペレーティングシステムでは、まさに fsync() システムコールは、ファイルのすべての未書き込みデータがフラッシュされるまで待機するべきですが、実際には、データが安定したストレージにフラッシュされる前に返される可能性があります。このため、オペレーティングシステムのクラッシュや停電によって最近コミットされたデータが破損したり、さらに最悪の場合、書き込み操作が再指示されたためにデータベースが破損したりすることもあります。データの完全性が重要である場合は、本番環境で何かを使用する前に、何らかの形で電源プラグを抜くテストを実行してください。OS X 10.3 以降の InnoDB では、特別な fcntl() ファイルフラッシュ方式が使用されます。Linux では、ライトバックキャッシュを無効にすることが推奨されています。

ATA/SATA ディスクドライブ上で hdparm -W0 /dev/hda のようなコマンドを使用すると、ライトバックキャッシュを無効にできる場合があります。一部のドライブやディスクコントローラでは、ライトバックキャッシュを無効にできない可能性があることに注意してください。

ユーザーを保護する InnoDB のリカバリ機能に関しては、InnoDB では二重書き込みバッファーと呼ばれる構造に関連したファイルフラッシュ技術が使用されています。これは、デフォルトで有効になっています (innodb_doublewrite=ON)。二重書き込みバッファーを使用すると、クラッシュや停電のあとのリカバリの安全性が高まるだけでなく、fsync() 操作の必要性が減るため、ほとんどの種類の Unix でパフォーマンスが向上します。データの完全性またはエラーの可能性に関心がある場合は、innodb_doublewrite オプションを有効のままにすることが推奨されています。二重書き込みバッファーの追加情報については、セクション14.10「InnoDB のディスク I/O とファイル領域管理」を参照してください。

注意

データの信頼性が考慮事項となっている場合は、NFS ボリューム上でデータファイルやログファイルが使用されるように InnoDB を構成しないでください。発生する可能性のある問題は、OS および NFS のバージョンによって異なります。これらの問題には、競合する書き込みからの保護が不足しているなどの問題や、最大ファイルサイズ上の制限などが含まれます。

InnoDB テーブルスペースファイルの場所とサイズの指定

InnoDB テーブルスペースファイルを設定するには、my.cnf オプションファイルの [mysqld] セクションで innodb_data_file_path オプションを使用します。Windows では、代わりに my.ini を使用できます。innodb_data_file_path の値は、1 つ以上のデータファイルのリストで指定するようにしてください。複数のデータファイル名を指定する場合は、セミコロン文字 (;) で区切ってください。

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

たとえば、次の設定では、最小サイズのシステムテーブルスペースが明示的に作成されます。

[mysqld]
innodb_data_file_path=ibdata1:12M:autoextend

この設定では、ibdata1 という名前の 12M バイトの自動拡張データファイルが 1 つ構成されます。ファイルの場所が指定されていないため、InnoDB によって、デフォルトで MySQL データディレクトリ内に作成されます。

K バイト、M バイト、または G バイトの単位を指定するために、サイズは KM、または G のサフィクス文字を使用して指定されます。

データディレクトリ内にある ibdata1 という名前の 50M バイトの固定サイズデータファイルと、ibdata2 という名前の 50M バイトの自動拡張ファイルを含むテーブルスペースは、次のように構成できます。

[mysqld]
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

データファイルを指定するための完全な構文には、ファイル名、そのサイズ、および複数のオプション属性が含まれています。

file_name:file_size[:autoextend[:max:max_file_size]]

autoextend および max 属性は、innodb_data_file_path 行内の最後のデータファイルでのみ使用できます。

最後のデータファイルに autoextend オプションを指定すると、テーブルスペースに空き領域がなくなった場合に、InnoDB はデータファイルを拡張します。デフォルトでは、一度に 8M バイトずつ増分されます。増分を変更するには、innodb_autoextend_increment システム変数を変更します。

ディスクがいっぱいになったら、別のディスク上に別のデータファイルを追加するといいでしょう。テーブルスペースを再構成する手順については、セクション14.5.7「InnoDB ログファイルの数またはサイズの変更、および InnoDB テーブルスペースのサイズの変更」を参照してください。

InnoDB ではファイルシステムの最大ファイルサイズが認識されないため、最大ファイルサイズが 2G バイトのような小さい値になっているファイルシステムでは注意してください。自動拡張データファイルの最大サイズを指定するには、autoextend 属性のあとに max 属性を使用してください。最大サイズを超えると致命的なエラーが発生し、クラッシュする可能性もあるため、ディスクの使用率を制約することが非常に重要である場合に限り、max 属性を使用してください。次の構成では、ibdata1 が最大で 500M バイトの制限まで増大することが許可されます。

[mysqld]
innodb_data_file_path=ibdata1:12M:autoextend:max:500M

InnoDB は、デフォルトで MySQL データディレクトリ内にテーブルスペースファイルを作成します。場所を明示的に指定するには、innodb_data_home_dir オプションを使用します。たとえば、ibdata1 および ibdata2 という名前の 2 つのファイルを使用するが、/ibdata ディレクトリ内に作成するには、次のように InnoDB を構成します。

[mysqld]
innodb_data_home_dir = /ibdata
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
注記

InnoDB ではディレクトリが作成されないため、サーバーを起動する前に、/ibdata ディレクトリが存在することを確認してください。このことは、ユーザーが構成するログファイルディレクトリにも当てはまります。必要なディレクトリを作成するには、Unix または DOS の mkdir コマンドを使用します。

MySQL サーバーがデータディレクトリ内にファイルを作成するための適切なアクセス権を持っていることを確認してください。さらに一般的に言えば、サーバーはデータファイルやログファイルを作成する必要のあるディレクトリ内に、アクセス権を持っている必要があります。

InnoDBinnodb_data_home_dir の値をテキストとしてデータファイル名に連結させ、必要に応じてパス名の区切り文字 (スラッシュまたはバックスラッシュ) を値の間に追加することで、各データファイルのディレクトリパスを形成します。my.cnfinnodb_data_home_dir オプションがまったく指定されていない場合は、デフォルト値がドットディレクトリ ./ (つまり、MySQL データディレクトリ) になります。(MySQL サーバーは実行の開始時に、現在の作業ディレクトリをそのデータディレクトリに変更します。)

innodb_data_home_dir を空の文字列として指定すると、innodb_data_file_path 値で一覧表示されたデータファイルに絶対パスを指定できます。次の例は、前述の例と同等です。

[mysqld]
innodb_data_home_dir =
innodb_data_file_path=/ibdata/ibdata1:50M;/ibdata/ibdata2:50M:autoextend

InnoDB 構成オプションの指定

小規模なシステム向けのサンプル my.cnf ファイル。512M バイトの RAM と 1 台のハードディスクが搭載されたコンピュータを使用すると仮定します。次の例では、autoextend 属性を含む、InnoDBmy.cnf または my.ini で指定可能な構成パラメータを示します。この例は、InnoDB データファイルとログファイルをいくつかのディスクに分散することを希望しない、Unix と Windows 両方のほとんどのユーザーに適しています。ここでは、MySQL データディレクトリ内に自動拡張データファイル ibdata1 と、2 つの InnoDB ログファイル ib_logfile0 および ib_logfile1 を作成します。

[mysqld]
# You can write your other MySQL server options here
# ...
# Data files must be able to hold your data and indexes.
# Make sure that you have enough free disk space.
innodb_data_file_path = ibdata1:12M:autoextend
#
# Set buffer pool size to 50-80% of your computer's memory
innodb_buffer_pool_size=256M
innodb_additional_mem_pool_size=20M
#
# Set the log file size to about 25% of the buffer pool size
innodb_log_file_size=64M
innodb_log_buffer_size=8M
#
innodb_flush_log_at_trx_commit=1

一部のファイルシステムでは、データファイルを 2G バイト未満にする必要があることに注意してください。ログファイルを結合したサイズは、最大で 512G バイトまでにすることができます。データファイルを結合したサイズは、10M バイトをわずかに超える大きさにする必要があります。

InnoDB システムテーブルスペースの設定

はじめて InnoDB システムテーブルスペースを作成する際は、コマンドプロンプトから MySQL サーバーを起動する方法が最適です。そのあと、データベースの作成に関する情報が InnoDB の画面に出力されるため、何が発生しているのかを確認できます。たとえば、Windows の場合、mysqldC:\Program Files\MySQL\MySQL Server 5.6\bin に配置されていれば、次のように起動できます。

C:\> "C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqld" --console

サーバーの出力が画面に送信されない場合は、サーバーのエラーログをチェックして、起動プロセス中に InnoDB から出力された内容を確認してください。

InnoDB で表示される情報の出力例については、セクション14.5.1「InnoDB テーブルスペースの作成」を参照してください。

MySQL 構成ファイルの編集

サーバーの起動時に読み取られる任意のオプションファイルの [mysqld] グループ内に、InnoDB オプションを配置できます。オプションファイルの場所については、セクション4.2.6「オプションファイルの使用」で説明されています。

インストールおよび構成ウィザードを使用して、MySQL を Windows 上にインストールした場合は、オプションファイルが MySQL インストールディレクトリ内に配置された my.ini ファイルになります。セクション2.3.3「MySQL Installer を使用した MySQL の Microsoft Windows へのインストール」を参照してください。

C: ドライブがブートドライブではないブートローダーが PC で使用されている場合は、Windows ディレクトリ (通常は C:\WINDOWS) 内の my.ini ファイルを使用することが唯一のオプションとなります。コンソールウィンドウ内のコマンドプロンプトで SET コマンドを使用すると、WINDIR の値を出力できます。

C:\> SET WINDIRwindir=C:\WINDOWS

mysqld で特定のファイルからのオプションのみが読み取られることを確認するには、サーバーの起動時に --defaults-file オプションをコマンド行の最初のオプションとして使用します。

mysqld --defaults-file=your_path_to_my_cnf

大規模なシステム向けのサンプル my.cnf ファイル。ディレクトリパス //dr2、および /dr3 に 2G バイトの RAM と 3 台の 60G バイトハードディスクが搭載された Linux コンピュータを使用すると仮定します。次の例では、InnoDBmy.cnf で指定可能な構成パラメータを示します。

[mysqld]
# You can write your other MySQL server options here
# ...
innodb_data_home_dir =
#
# Data files must be able to hold your data and indexes
innodb_data_file_path = /db/ibdata1:2000M;/dr2/db/ibdata2:2000M:autoextend
#
# Set buffer pool size to 50-80% of your computer's memory,
# but make sure on Linux x86 total memory usage is < 2GB
innodb_buffer_pool_size=1G
innodb_additional_mem_pool_size=20M
innodb_log_group_home_dir = /dr3/iblogs
#
# Set the log file size to about 25% of the buffer pool size
innodb_log_file_size=250M
innodb_log_buffer_size=8M
#
innodb_flush_log_at_trx_commit=1
innodb_lock_wait_timeout=50
#
# Uncomment the next line if you want to use it
#innodb_thread_concurrency=5

InnoDB の最大メモリー割り当ての決定

警告

32 ビット版の GNU/Linux x86 では、高すぎるメモリー使用率を設定しないように注意してください。glibc では、プロセスヒープがスレッドスタック上で増加することが許可されている可能性があるため、サーバーがクラッシュします。次の式の値が 2G バイトに近づいていたり、超えていたりする場合は危険です。

innodb_buffer_pool_size
+ key_buffer_size
+ max_connections*(sort_buffer_size+read_buffer_size+binlog_cache_size)
+ max_connections*2MB

各スレッドではスタックが使用され (多くの場合は 2M バイトですが、Oracle Corporation が提供する MySQL バイナリでは 256K バイトだけです)、最悪のケースでは、sort_buffer_size + read_buffer_size の追加メモリーも使用されます。

その他の mysqld サーバーパラメータの調整。次の値は典型的であり、ほとんどのユーザーに適しています。

[mysqld]
skip-external-locking
max_connections=200
read_buffer_size=1M
sort_buffer_size=1M
#
# Set key_buffer to 5 - 50% of your RAM depending on how much
# you use MyISAM tables, but keep key_buffer_size + InnoDB
# buffer pool size < 80% of your RAM
key_buffer_size=value

Linux の場合、カーネルで大規模ページのサポートが有効になっていれば、InnoDB は、バッファープールや追加メモリープールのメモリーを割り当てる際に大規模なページを使用できます。セクション8.11.4.2「ラージページのサポートの有効化」を参照してください。

14.3.1 読み取り専用操作用の InnoDB の構成

現在は、サーバーの起動時に --innodb-read-only 構成オプションを有効にすることで、MySQL データディレクトリが読み取り専用メディア上にある InnoDB テーブルでクエリーを実行できます。

有効にする方法

読み取り操作用にインスタンスを準備するには、必要なすべての情報が読み取り専用メディア上に格納される前に、データファイルにフラッシュされることを確認します。変更バッファーが無効になっている (innodb_change_buffering=0) サーバーを実行し、低速シャットダウンを実行します。

MySQL インスタンス全体にわたって読み取り専用モードを有効にするには、サーバーの起動時に次の構成オプションを指定します。

  • --innodb-read-only=1

  • インスタンスが DVD や CD などの読み取り専用メディア上にある場合、または /var ディレクトリがすべてのユーザーから書き込み可能でない場合: --pid-file=path_on_writeable_media および --event-scheduler=disabled

使用シナリオ

この操作モードは、次のような状況に適しています。

  • DVD や CD などの読み取り専用ストレージメディア上に、MySQL アプリケーションまたは MySQL データセットを配布する。

  • (一般に、データウェアハウス構成で) 同じデータディレクトリで同時にクエリーを実行する複数の MySQL インスタンス。この方法を使用すれば、負荷の高い MySQL インスタンスで発生する可能性のあるボトルネックを回避したり、さまざまなインスタンスに対してさまざまな構成オプションを使用して、特定の種類のクエリーを個別に調整したりできる場合があります。

  • 安全性またはデータの完全性の理由により読み取り専用の状態になったデータ (アーカイブされたバックアップデータなど) のクエリーを実行する。

注記

この機能の目的は、読み取り専用の側面に基づいた生のパフォーマンスではなく、主に配布および配備する際の柔軟性です。サーバー全体を読み取り専用にする必要なしで、読み取り専用クエリーのパフォーマンスを調整する方法については、セクション14.13.14「InnoDB の読み取り専用トランザクションの最適化」を参照してください。

動作

--innodb-read-only オプションを使用して、サーバーが読み取り専用モードで実行されると、特定の InnoDB 機能およびコンポーネントが減少したり、完全に無効になったりします。

  • 変更バッファー (特に、変更バッファーからのマージ) は実行されません。読み取り専用操作用にインスタンスを準備するときに、変更バッファーが空になっていることを確認するには、変更バッファーを無効にして (innodb_change_buffering=0)、まず低速シャットダウンを実行します。

  • 起動時にはクラッシュリカバリフェーズがありません。インスタンスを読み取り専用状態にする前に、低速シャットダウンが実行されている必要があります。

  • 読み取り専用操作では Redo ログが使用されないため、インスタンスを読み取り専用にする前に、innodb_log_file_size を最小限のサイズ (1M バイト) に設定できます。

  • I/O 読み取りスレッド以外のバックグラウンドスレッドがすべて無効になります。その結果、読み取り専用インスタンスでデッドロックが発生する可能性がなくなります。

  • デッドロックに関する情報やモニターの出力などは、一時ファイルに書き込まれません。その結果、SHOW ENGINE INNODB STATUS で出力が生成されなくなります。

  • --innodb-read-only を使用して MySQL サーバーが起動されているが、まだデータディレクトリが書き込み可能メディア上にある場合は、root ユーザーが引き続き、GRANTREVOKE などの DCL 操作を実行できます。

  • 構成オプションの設定を変更すると、通常は書き込み操作の動作が変更されますが、サーバーが読み取り専用モードになっている場合は影響がありません。

  • 分離レベルを強制的に適用する MVCC 処理が無効になります。更新も削除もできないため、すべてのクエリーで最新バージョンのレコードが読み取られます。

  • Undo ログは使用されません。innodb_undo_tablespaces および innodb_undo_directory 構成オプションの設定を無効にします。

14.4 InnoDB の管理

InnoDB に関連する管理タスクには、主に次のような側面が伴います。

  • システムテーブルスペースInnoDB テーブル、およびそれらに関連付けられたインデックスを表すデータファイルの管理。これらのファイルをレイアウトおよび分割する方法は変更できますが、特定のテーブルで実現可能なパフォーマンスと機能の両方が影響を受けます。

  • クラッシュリカバリで使用される Redo ログファイルの管理。これらのファイルのサイズを指定できます。

  • InnoDB が別のストレージエンジンでなく、目的のテーブルで使用されているかどうかの確認。

  • パフォーマンスに関連する一般的な管理タスク。アプリケーションの設計フェーズ時にアプリケーション開発者に相談したり、システム設定が正常に機能していることを確認するために継続的にパフォーマンスをモニターしたり、突然に発生したパフォーマンスや容量の問題を診断して修正したりする場合があります。

現在は InnoDB テーブルが MySQL のデフォルトであるため、関連する管理資料の大半は主要な管理の章、第5章「MySQL サーバーの管理に記載されています。

14.5 InnoDB テーブルスペース管理

14.5.1 InnoDB テーブルスペースの作成

MySQL をインストールし、必要な InnoDB 構成パラメータが含まれるようにオプションファイルを編集したと仮定します。MySQL を起動する前に、InnoDB のデータファイルおよびログファイルに指定したディレクトリが存在し、MySQL サーバーがそれらのディレクトリへのアクセス権を持っていることを確認します。InnoDB はファイルだけを作成し、ディレクトリは作成しません。データファイルおよびログファイル用のディスク領域が十分にあることもチェックします。

InnoDB が有効になっている状態でサーバーをはじめて起動するときの最適な方法は、MySQL サーバー mysqldmysqld_safe からでも、Windows サービスとしてでもなく、コマンドプロンプトから実行することです。コマンドプロンプトから実行すると、mysqld で出力される内容および発生している事象が表示されます。Unix では、単に mysqld を呼び出すだけです。Windows では、出力先がコンソールウィンドウになるように、--console オプションを付けて mysqld を起動します。

オプションファイル内ではじめて InnoDB を構成したあとに、MySQL サーバーを起動すると、InnoDB によってデータファイルおよびログファイルが作成され、次のような内容が出力されます。

InnoDB: The first specified datafile /home/heikki/data/ibdata1
did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file /home/heikki/data/ibdata1 size to 134217728
InnoDB: Database physically writes the file full: wait...
InnoDB: datafile /home/heikki/data/ibdata2 did not exist:
new to be created
InnoDB: Setting file /home/heikki/data/ibdata2 size to 262144000
InnoDB: Database physically writes the file full: wait...
InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist:
new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile0 size
to 5242880
InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist:
new to be created
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile1 size
to 5242880
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
InnoDB: Started
mysqld: ready for connections

この時点で、InnoDB によってテーブルスペースおよびログファイルが初期化されています。mysql と同様に、通常の MySQL クライアントプログラムを使用して MySQL サーバーに接続できます。mysqladmin shutdown を使用して MySQL サーバーをシャットダウンすると、次のように出力されます。

010321 18:33:34 mysqld: Normal shutdown
010321 18:33:34 mysqld: Shutdown Complete
InnoDB: Starting shutdown...
InnoDB: Shutdown completed

データファイルおよびログディレクトリを調査すれば、そこに作成されたファイルを確認できます。MySQL が再起動されるときには、データファイルおよびログファイルはすでに作成されているため、出力はさらに簡潔になります。

InnoDB: Started
mysqld: ready for connections

innodb_file_per_table オプションを my.cnf に追加すると、InnoDB では各テーブルが、.frm ファイルが作成された場所と同じ MySQL データベースディレクトリにある独自の .ibd ファイルに格納されます。セクション14.5.2「InnoDB File-Per-Table モード」を参照してください。

14.5.2 InnoDB File-Per-Table モード

従来、InnoDB のすべてのテーブルとインデックスは、システムテーブルスペースに格納されていました。このモノリシック方式は、データの拡大を綿密に計画した、データベース処理に完全に特化したマシンに対象を絞った方式です。この方式では、MySQL に割り当てられるどのディスクストレージも、他の目的のために要求されることはありません。InnoDBfile-per-table モードは、InnoDB の各テーブルとそのインデックスを個別のファイルに格納する方式の、柔軟性を向上した代替手段です。.ibd のような各ファイルは、それぞれのテーブルスペースを表します。このモードは innodb_file_per_table 構成オプションで制御され、MySQL 5.6.6 以降ではデフォルトです。

File-Per-Table モードの利点

  • テーブルを切り詰めたり、削除したりするときに、オペレーティングシステムのディスクスペースを再利用できます。file-per-table モードがオフに切り替えられたときに作成されたテーブルの場合、テーブルを切り詰めたり、削除したりすると、内部的に ibdata ファイルに空き領域が作成されますが、その空き領域は新しい InnoDB データにのみ使用できます。

  • TRUNCATE TABLE 操作は、個々の .ibd ファイルで実行する場合よりも高速です。

  • I/O の最適化、容量管理、またはバップアップのために、特定のテーブルを別々のストレージデバイスに格納することができます。前のリリースでは、セクション8.11.3.1「シンボリックリンクの使用」で述べられているように、ほかのドライブにデータベースディレクトリ全体を移動し、MySQL データディレクトリにシンボリックリンクを作成する必要がありました。MySQL 5.6.6 以降では、セクション14.5.4「テーブルスペースの位置の指定」で述べられているように、構文 CREATE TABLE ... DATA DIRECTORY = absolute_path_to_directory を使用して各テーブルの位置を特定できます。

  • OPTIMIZE TABLE を実行して、テーブルスペースを圧縮または再作成できます。OPTIMIZE TABLE を実行すると、InnoDB は実際のデータの格納に必要なスペースだけを使用して、一時名を持つ新しい .ibd ファイルを作成します。最適化が完了すると、InnoDB は古い .ibd ファイルを削除し、新しい .ibd ファイルで置き換えます。前の .ibd ファイルは非常に大きくなったが、実際のデータはそのサイズの一部を占めるだけの場合、OPTIMIZE TABLE を実行すると、未使用領域を再利用できます。

  • データベース全体ではなく、個別の InnoDB テーブルを移動できます。

  • ある MySQL インスタンスから別のインスタンスに個別の InnoDB テーブルをコピーできます (トランスポータブルテーブルスペース 機能として知られています)。

  • innodb_file_per_table が有効なときに作成されたテーブルは、Barracuda ファイル形式を使用できます。Barracuda ファイル形式は、圧縮 および ダイナミック の行フォーマットなどの機能に対応します。innodb_file_per_table がオフのときに作成されたテーブルは、これらの機能を使用できません。これらの機能を既存のテーブルに利用するには、file-per-table 設定をオンにして、既存のテーブルで ALTER TABLE t ENGINE=INNODB を実行します。テーブルを変換する前に、セクション14.6.4「MyISAM から InnoDB へのテーブルの変換」を参照してください。

  • ダイナミック行フォーマットを使用して、大きな BLOB またはテキストカラムを持つテーブルでストレージ効率を向上させることができます。

  • innodb_file_per_table を使用すると、リカバリが成功する可能性が高くなることがあります。また破損が発生した場合、サーバーが再起動できない場合、またはバックアップおよびバイナリログが使用できない場合に、時間が節約できる可能性があります。

  • MySQL Enterprise Backup 製品を使用して、他の InnoDB テーブルの使用を中断せずに、単一のテーブルを迅速にバックアップしたり、リストアしたりできます。詳細は、Partial Backup and Restore Optionsを参照してください。

  • File-per-table モードを使用すると、バックアップからテーブルを除外できます。これは、それほど頻繁にバックアップを取る必要のないテーブル、または別のスケジュールでバックアップが必要なテーブルに有効です。

  • file-per-table モードは、テーブルをコピーまたはバックアップするときにレポートする、テーブルごとのステータスに便利です。

  • file-per-table モードを使用すると、MySQL にアクセスせずに、ファイルシステムレベルでテーブルサイズをモニターできます。

  • 一般的な Linux ファイルシステムでは、innodb_flush_methodO_DIRECT に設定されていると、1 つのファイルへの並列書き込みは許可されていません。その結果、innodb_flush_method と併せて innodb_file_per_table を使用すると、パフォーマンスが向上する可能性があります。

  • innodb_file_per_table が無効な場合、テーブル、データディクショナリ、および Undo ログに対して 1 つの共有テーブルスペース (システムテーブルスペース) があります。この 1 つのテーブルスペースのサイズの制限値は 64TB です。innodb_file_per_table が有効である場合、各テーブルには独自のテーブルスペースがあり、各テーブルスペースのサイズの制限値は 64TB です。関連情報については、セクションD.10.3「テーブルサイズの制限」を参照してください。

File-Per-Table モードの考えられる短所

  • innodb_file_per_table の場合、各テーブルには未使用のテーブルスペースがある場合があり、そのテーブルスペースを利用できるのは同じテーブルの行だけです。これは、テーブルスペースが適切に管理されていないと、無駄なテーブルスペースが減るのではなく、増える結果となる可能性があります。

  • fsync 操作は、1 つのファイルではなく、各オープンテーブルで実行する必要があります。ファイルごとに別々の fsync 操作があるため、複数のテーブルへの書き込み操作を 1 つの I/O 操作に結合することはできません。このため、InnoDBfsync 操作の総数を増やして実行する必要がある可能性があります。

  • mysqld では、テーブル当たり 1 つのオープンファイルの処理を維持する必要があるため、大量のテーブルがある場合、パフォーマンスに影響が出る可能性があります。

  • より多くのファイルディスクリプタが使用されます。

  • innodb_file_per_table は、MySQL 5.6.6 以降ではデフォルトでオンです。MySQL 5.5 または 5.1 との下位互換性に懸念がある場合、無効化の検討をお勧めします。innodb_file_per_table を無効にすると、ALTER TABLE がテーブル (ALGORITHM=COPY) を再作成する場合、ALTER TABLEInnoDB テーブルがシステムのテーブルスペースから個々の .ibd ファイルに移動するのが抑えられます。

    たとえば、InnoDB テーブルのクラスタインデックスを再構築する場合、テーブルはinnodb_file_per_table の現在の設定を使用して再作成されます。この動作は、InnoDB のセカンダリインデックスを追加または削除するときには適用されません。セカンダリインデックスがテーブルを再構築しないで作成された場合、現在の innodb_file_per_table 設定にかかわらず、そのインデックスはテーブルデータと同じファイルに格納されます。

  • テーブルが増えていくと、DROP TABLE およびテーブルスキャンのパフォーマンスが下がることがあるフラグメンテーションが増える可能性があります。しかし、フラグメンテーションが管理されている場合、ファイル自身のテーブルスペース内にファイルがあると、パフォーマンスが向上する可能性があります。

  • バッファープールはテーブルごとのテーブルスペースを削除するときにスキャンされるため、サイズが数十ギガバイトのバッファープールに数秒かかる場合があります。スキャンは広範囲に内部ロックをかけて実行されるため、他の操作を遅らせる場合があります。共有テーブルスペース内のテーブルには影響ありません。

  • 自動拡張の共有テーブルスペースが満杯になったときに、そのサイズを拡張する場合の増分サイズ (MB 単位) を定義する innodb_autoextend_increment 変数は、file-per-table テーブルスペースファイルに適用されません。innodb_autoextend_increment の値にかかわらず、file-per-table テーブルスペースファイルは自動拡張です。拡張は少量で始まり、その後の拡張は増分が 4MB で発生します。

14.5.3 File-Per-Table モードの有効化および無効化

file-per-table モードを MySQL サーバーのデフォルトにするには、--innodb_file_per_table コマンド行オプションでサーバーを起動するか、my.cnf[mysqld] セクションに次の行を追加します。

[mysqld]
innodb_file_per_table

サーバーが動作している間に、コマンドを発行することもできます。

SET GLOBAL innodb_file_per_table=1;

file-per-table モードが有効な場合、InnoDB は、適切なデータベースディレクトリ内の独自の tbl_name.ibd ファイルに、新しく作成された各テーブルを格納します。MyISAM ストレージエンジンとは異なり、インデックスとデータにそれぞれ tbl_name.MYDtbl_name.MYI ファイルがあると、InnoDB はデータとインデックスを一緒に 1 つの .ibd ファイルに格納します。それでも、tbl_name.frm ファイルは従来どおり作成されます。

使用する起動オプションから innodb_file_per_table を削除してサーバーを再起動する場合、または SET GLOBAL コマンドでオプションをオフにした場合、InnoDB はシステムのテーブルスペース内に新しいテーブルを作成します。

file-per-table 設定にかかわらず、InnoDB テーブルの読み取りおよび書き込みは常に実行できます。

テーブルをシステムテーブルスペースから自身のテーブルスペースへ移動するには、またはその反対方向にテーブルを移動するには、innodb_file_per_table 設定を変更してテーブルを再作成します。

-- Move table from system tablespace to its own tablespace.
SET GLOBAL innodb_file_per_table=1;
ALTER TABLE table_name ENGINE=InnoDB;
-- Move table from its own tablespace to system tablespace.
SET GLOBAL innodb_file_per_table=0;
ALTER TABLE table_name ENGINE=InnoDB; 
注記

InnoDB は、内部のデータディクショナリUndo ログをシステムのテーブルスペースに配置するため、常にこのテーブルスペースが必要です。.ibd ファイルは InnoDB が動作するのには十分ではありません。

システムテーブルスペースから独自の .ibd ファイルにテーブルが移動された場合、システムテーブルスペースを構成するデータファイルのサイズは維持されます。以前にテーブルが占有したスペースは、新しい InnoDB データ用に再利用できますが、オペレーティングシステム用には再利用されません。システムテーブルスペースから、ディスクスペースが限られているところへ大規模な InnoDB テーブルを移動する場合、innodb_file_per_table をオンにしてから mysqldump コマンドを使用してインスタンス全体を再作成することをお勧めします。

14.5.4 テーブルスペースの位置の指定

新しい InnoDBfile-per-table テーブルスペースを MySQL データディレクトリの外側の特定の位置に作成するには、CREATE TABLE ステートメントの DATA DIRECTORY = absolute_path_to_directory 句を使用します。

あらかじめ位置について計画を立てます。ALTER TABLE ステートメントで DATA DIRECTORY 句を使用できないためです。指定するディレクトリは、高速の SSD や大容量の HDD など、パフォーマンスや容量に際だった特徴のあるほかのストレージデバイス上に置くことも可能です。

MySQL は、目的のディレクトリ内にデータベース名に対応するサブディレクトリを作成し、その中に、新しいテーブル用の .ibd ファイル を作成します。MySQL は、MySQL DATADIR ディレクトリの下のデータベースディレクトリに、テーブルのパス名を含む table_name.isl ファイル作成します。.isl file は MySQL によってシンボリックリンクのように処理されます。(実際のシンボリックリンクを使用することInnoDB テーブルではサポートされませんでした。)

次の例では、MySQL の開発またはテスト用の小さなインスタンスを、95% が使用済みのプライマリハードドライブを搭載したノート型パソコンで実行し、空きスペースが多い別のストレージデバイス上に名前が EXTERNAL の新しいテーブルを配置する方法について示します。シェルコマンドは、DATADIR ディレクトリの下のデフォルトの位置にある LOCAL テーブルおよび指定した位置にある EXTERNAL テーブルへのさまざまなパスを示します。

mysql> \! df -k .
Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted on
/dev/disk0s2 244277768 231603532 12418236 95% 57964881 3104559 95% /
mysql> use test;
Database changed
mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.00 sec)
mysql> \! pwd
/usr/local/mysql
mysql> create table local (x int unsigned not null primary key);
Query OK, 0 rows affected (0.03 sec)
mysql> \! ls -l data/test/local.ibd
-rw-rw---- 1 cirrus staff 98304 Nov 13 15:24 data/test/local.ibd
mysql> create table external (x int unsigned not null primary key) data directory = '/volumes/external1/data';
Query OK, 0 rows affected (0.03 sec)
mysql> \! ls -l /volumes/external1/data/test/external.ibd
-rwxrwxrwx 1 cirrus staff 98304 Nov 13 15:34 /volumes/external1/data/test/external.ibd
mysql> select count(*) from local;
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.01 sec)
mysql> select count(*) from external;
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.01 sec)
注:
  • 最初、MySQL は .ibd ファイルを開いたままにして、デバイスがマウント解除されないようにしていますが、サーバーがビジーになると、結果的にテーブルを閉じることになる場合があります。MySQL の動作中に誤って外部デバイスをマウント解除したり、デバイスが接続されていないときに MySQL を起動したりしないように注意してください。関連する .ibd ファイルが欠けているときにテーブルにアクセスしようとすると、サーバーの再起動が必要となる重大なエラーの原因となります。

    それでも .ibd ファイルが期待するパス上にない場合、サーバーの再起動が失敗する可能性があります。この場合、手動でデータベースディレクトリ内の table_name.isl ファイルを削除し、再起動後に DROP TABLE を実行して .frm ファイルを削除し、テーブルに関する情報をデータディクショナリから削除します。

  • NFS がマウントされたボリュームに MySQL テーブルを配置しないでください。NFS はメッセージパッシングプロトコルを使用してファイルに書き込むため、ネットワークメッセージが失われたり、順序どおりに受信しなかったりした場合に、データの一貫性が失われる原因となる可能性があります。

  • LVM スナップショット、ファイルのコピー、または他のファイルベースのメカニズムを使用して、.ibd ファイルのバックアップを取る場合、必ず最初に FLUSH TABLES ... FOR EXPORT ステートメントを使用して、メモリーにバッファリングされたすべての変更が、バックアップを行う前にディスクにフラッシュされていることを確認します。

  • DATA DIRECTORY 句は シンボリックリンクの使用 のサポート済み代替手段です。これはずっと問題があり、各 InnoDB テーブルには決してサポートされませんでした。

14.5.5 テーブルスペースの別のサーバーへのコピー (トランスポータブルテーブルスペース)

このセクションでは、Transportable Tablespace 機能を使用して、file-per-table テーブルスペース (.idb ファイル) をあるデータベースサーバーから別のデータベースサーバーにコピーする方法について説明します。

他の InnoDB テーブルコピー方式について詳しくは、セクション14.6.2「別のマシンへの InnoDB テーブルの移動またはコピー」を参照してください。

InnoDBfile-per-table テーブルスペースを別のデータベースサーバーにコピーすることをお勧めするのには、多くの理由があります。

  • 本番サーバーに余計な負荷を掛けずにレポートを実行するため。

  • 新しいスレーブサーバーに、あるテーブルとまったく同じデータをセットアップするため。

  • 問題や誤りが発生したあとに、テーブルのバックアップ版をリストアするため。

  • mysqldump コマンドの結果をインポートするよりも、データを移動させる方が速いため。データの再挿入とインデックスの再構築を行うよりも、データがすぐに使用できるためです。

  • システム要件により適したストレージ媒体を持つサーバーに file-per-table テーブルスペースを移動するため。たとえば、アクセス頻度の高いテーブルを SSD デバイスに置いたり、大規模なテーブルを大容量の HDD デバイスに置いたりする場合です。

テーブルスペースのコピーの制限と使用方法に関する注意 (トランスポータブルテーブルスペース)

  • テーブルスペースのコピー手順は、innodb_file_per_tableON (MySQL 5.6.6 以降ではデフォルトです) に設定されている場合にのみ可能です。共有のシステムテーブルスペースにあるテーブルは休止できません。

  • テーブルが休止されると、影響を受けたテーブルでは読み取り専用のトランザクションのみが許可されます。

  • テーブルスペースをインポートする場合、ページサイズはインポートするインスタンスのページサイズに一致する必要があります。

  • DISCARD TABLESPACE がパーティション化されたテーブルでサポートされていないということは、トランスポータブルテーブルスペースも未サポートであることを意味します。パーティション化されたテーブルで ALTER TABLE ... DISCARD TABLESPACE を実行すると、次のエラーが返されます。ERROR 1031 (HY000): Table storage engine for 'part' doesn't have this option.

  • DISCARD TABLESPACE は、foreign_key_checks1 に設定されている親/子 (主キー/外部キー) 関係を持つテーブルスペースをサポートしていません。親子関係のテーブルのテーブルスペースを破棄する前に、foreign_key_checks=0 を設定します。

  • ALTER TABLE ... IMPORT TABLESPACE は、インポートされたデータに対して外部キー制約を課しません。テーブル間に外部キー制約がある場合、すべてのテーブルを同じ (論理上の) 時点でエクスポートしてください。

  • ALTER TABLE ... IMPORT TABLESPACE では、テーブルスペースをインポートするための .cfg メタデータファイルは必要ありません。ただし、.cfg ファイルなしでインポートした場合は、メタデータのチェックは実行されず、次に類似した警告が発行されます。

    Message: InnoDB: IO Read error: (2, No such file or directory) Error opening '.\
    test\t.cfg', will attempt to import without schema verification
    1 row in set (0.00 sec) 

    .cfg ファイルなしでインポートする機能は、スキーマの不一致が予想されない場合に、使い勝手が高まる可能性があります。また、.cfg ファイルなしでインポートする機能は、メタデータが .ibd ファイルから収集できないクラッシュリカバリシナリオで役立つ可能性があります。

  • MySQL 5.6 以降では、両方のサーバーが GA (一般提供) ステータスであり、両者のバージョンが同じシリーズである場合に、テーブルスペースファイルの別のサーバーからのインポートが機能します。そうでないと、インポート先のサーバーにファイルが作成されていなければなりません。

  • レプリケーションシナリオでは、マスターとスレーブの両方で innodb_file_per_tableON に設定されている必要があります。

  • Windows では、InnoDB はデータベース、テーブルスペース、およびテーブル名を内部的に小文字で格納します。Linux や UNIX など、大文字と小文字を区別するオペレーティングシステムでインポートの問題を回避するには、すべてのデータベース、テーブルスペース、およびテーブルを小文字名を使用して作成します。これを遂行する便利な方法は、データベース、テーブルスペース、またはテーブルを作成する前に、my.cnf または my.ini ファイルの [mysqld] セクションに次の行を追加することです。

    [mysqld]
    lower_case_table_names=1

手順の例: あるサーバーから別のサーバーへのテーブルスペースのコピー (トランスポータブルテーブルスペース)

この手順では、MySQL の実行中のサーバーインスタンスから実行中の別のインスタンスへテーブルをコピーする方法について説明します。同じ手順は、微調整を加えると、同じインスタンスでテーブルの完全なリストアを実行するために使用できます。

  1. ソースサーバーで、テーブルがまだ存在していない場合、テーブルを作成します。

    mysql> use test;
    mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
  2. 目的サーバーで、テーブルが存在していない場合、テーブルを作成します。

    mysql> use test;
    mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
  3. 目的サーバーで、既存のテーブルスペースを破棄します。(テーブルスペースをインポートする前に、InnoDB は受け取り側のテーブルにアタッチされたテーブルスペースを破棄します。)

    mysql> ALTER TABLE t DISCARD TABLESPACE;
  4. ソースサーバーでは、FLUSH TABLES ... FOR EXPORT を実行してテーブルを休止し、.cfg メタデータファイルを作成します。

    mysql> use test;
    mysql> FLUSH TABLES t FOR EXPORT;

    メタデータ (.cfg) ファイルは InnoDB データディレクトリに作成されます。

    注記

    FLUSH TABLES ... FOR EXPORT は MySQL 5.6.6 以降で使用できます。このステートメントは、サーバー稼働中にバイナリテーブルのコピーができるように、名前付きテーブルへの変更をディスクにフラッシュします。FLUSH TABLES ... FOR EXPORT が実行されると、InnoDB はテーブルと同じデータベースディレクトリに .cfg ファイルを作成します。.cfg ファイルには、テーブルスペースファイルをインポートするときのスキーマの検証に使用されるメタデータが含まれます。

  5. .ibd ファイルおよび .cfg メタデータファイルをソースサーバーから目的サーバーにコピーします。例:

    shell> scp /path/to/datadir/test/t.{ibd,cfg} destination-server:/path/to/datadir/test
    注記

    .ibd ファイルおよび .cfg ファイルは、次の手順で示すように、共有ロックを解放する前にコピーする必要があります。

  6. ソースサーバーでは、UNLOCK TABLES を使用して、FLUSH TABLES ... FOR EXPORT によって取得されたロックを解放します。

    mysql> use test;
    mysql> UNLOCK TABLES;
  7. 目的サーバーで、テーブルスペースをインポートします。

    mysql> use test;
    mysql> ALTER TABLE t IMPORT TABLESPACE;
    注記

    ALTER TABLE ... IMPORT TABLESPACE 機能は、インポートされたデータに対して外部キー制約を課しません。テーブル間に外部キー制約がある場合、すべてのテーブルを同じ (論理上の) 時点でエクスポートしてください。この場合、テーブルの更新を停止し、すべてのトランザクションをコミットし、テーブルで共有ロックを取得してから、エクスポート操作を実行します。

テーブルスペースのコピーの内部情報 (トランスポータブルテーブルスペース)

次の情報では、トランスポータブルテーブルスペースのコピー手順に関する内部情報とエラーログについて説明します。

ALTER TABLE ... DISCARD TABLESPACE が目的のインスタンスで実行された場合。

  • テーブルは X モードでロックされています。

  • テーブルスペースがテーブルから切り離されています。

FLUSH TABLES ... FOR EXPORT がソースインスタンスで実行された場合。

  • エクスポートのためにフラッシュされたテーブルが共有モードでロックされています。

  • パージコーディネータのスレッドが停止しています。

  • ダーティーページがディスクに同期しています。

  • テーブルのメタデータがバイナリの .cfg ファイルに書き込まれました。

この操作で予想されるエラーログメッセージです。

2013-07-18 14:47:31 34471 [Note] InnoDB: Sync to disk of '"test"."t"' started.
2013-07-18 14:47:31 34471 [Note] InnoDB: Stopping purge
2013-07-18 14:47:31 34471 [Note] InnoDB: Writing table metadata to './test/t.cfg'
2013-07-18 14:47:31 34471 [Note] InnoDB: Table '"test"."t"' flushed to disk 

UNLOCK TABLES がソースインスタンスで実行された場合。

  • バイナリの .cfg ファイルが削除されました。

  • インポートされたテーブル (または複数のテーブル) の共有ロックが解放され、パージコーディネータのスレッドが再起動されました。

この操作で予想されるエラーログメッセージです。

2013-07-18 15:01:40 34471 [Note] InnoDB: Deleting the meta-data file './test/t.cfg'
2013-07-18 15:01:40 34471 [Note] InnoDB: Resuming purge

ALTER TABLE ... IMPORT TABLESPACE が目的のインスタンスで実行されると、インポートのアルゴリズムはインポートされたテーブルスペースごとに次の操作を実行します。

  • テーブルスペースの各ページに破損があるかどうかをチェックします。

  • 各ページのスペース ID とログシーケンス番号 (LSN) が更新されます。

  • フラグが検証され、ヘッダーページの LSN が更新されます。

  • B ツリーページが更新されます。

  • ページの状態がディスクに書き込まれるように、この状態をダーティーに設定します。

この操作で予想されるエラーログメッセージです。

2013-07-18 15:15:01 34960 [Note] InnoDB: Importing tablespace for table 'test/t' that was exported from host 'ubuntu'
2013-07-18 15:15:01 34960 [Note] InnoDB: Phase I - Update all pages
2013-07-18 15:15:01 34960 [Note] InnoDB: Sync to disk
2013-07-18 15:15:01 34960 [Note] InnoDB: Sync to disk - done!
2013-07-18 15:15:01 34960 [Note] InnoDB: Phase III - Flush changes to disk
2013-07-18 15:15:01 34960 [Note] InnoDB: Phase IV - Flush complete 
注記

テーブルスペースが破棄されたこと (目的のテーブルのテーブルスペースを破棄した場合) を伝える警告、および .ibd ファイルがないために統計値が計算できなかったことを伝えるメッセージも受け取る場合があります。

2013-07-18 15:14:38 34960 [Warning] InnoDB: Table "test"."t" tablespace is set as discarded.
2013-07-18 15:14:38 7f34d9a37700 InnoDB: cannot calculate statistics for table "test"."t" because the .ibd file is missing. For help, please refer to
http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.html

14.5.6 個別のテーブルスペースへの InnoDB Undo ログの格納

MySQL 5.6.3 以降は、システムテーブルスペースを除く 1 つ以上の個別の Undo テーブルスペースInnoDBUndo ログを格納することができます。このレイアウトは、Undo ログが システムテーブルスペースの一部であるデフォルト構成とは異なります。Undo ログの I/O パターンにより、これらのテーブルスペースは SSD ストレージへの移動に適した候補になります。一方、システムテーブルスペースはハードディスクストレージに維持します。ユーザーは、InnoDB の Undo ログを保持するために作成された個々のテーブルスペース、およびそのテーブルスペース内の各セグメントを削除できません。

これらのファイルで、システムテーブルスペース内で以前に実行された I/O 操作を処理するため、これらの新しいファイルを加えるように、システムテーブルスペースの定義を拡張します。

Undo ログはロールバックセグメントとしても知られています。

この機能には、次の新しい構成オプションまたは名前の変わった構成オプションが含まれます。

  • innodb_undo_tablespaces

  • innodb_undo_directory

  • innodb_rollback_segmentsinnodb_undo_logs になります。互換性のため、古い名前も使用できます。

InnoDBUndo ログ機能には 2 つの非動的起動変数 (innodb_undo_tablespaces および innodb_undo_directory) の設定を伴うため、この機能は MySQL インスタンスを初期化する場合にのみ有効化できます。

使用上の注意

この機能を使用するには、次の手順に従います。

  1. Undo ログを保持するパスを決めます。MySQL 構成ファイルまたは起動スクリプトにある innodb_undo_directory オプションの引数としてそのパスを指定します。

  2. innodb_undo_logs オプションにゼロでない開始値を指定します。比較的小さい値から始めて、パフォーマンスの効果を調べて徐々に値を増やすことができます。

  3. innodb_undo_tablespaces オプションにゼロでない値を指定します。innodb_undo_logs 値で指定された複数の Undo ログは、この数の個々のテーブルスペース (.ibd ファイルで指定) に分割されます。この値は、MySQL インスタンスが有効である間は固定されるため、最適値が確かでない場合は、どちらかというと高く見積もります。

  4. 構成ファイルまたは MySQL 起動スクリプトで選択した値を使用して、新しい MySQL インスタンスを作成します。本番サーバーに類似したデータ量の現実的なワークロードを使用します。また、トランスポータブルテーブルスペース機能を使用して、既存のデータベースのテーブルを新しく構成した MySQL インスタンスにコピーします。詳細は、セクション14.5.5「テーブルスペースの別のサーバーへのコピー (トランスポータブルテーブルスペース)」を参照してください。

  5. I/O が多いワークロードのパフォーマンスのベンチマーク。

  6. 繰り返し、innodb_undo_logs の値を増やして、パフォーマンステストをやり直します。I/O パフォーマンスゲインが停止する値を見つけます。

  7. これらのオプションに理想的な設定を使用して、新しい本番インスタンスを配備します。レプリケーション構成でスレーブサーバーとして設定するか、以前の本番インスタンスからデータを移動します。

パフォーマンスおよびスケーラビリティーに関する考慮事項

Undo ログを個々のファイルに保持すると、MySQL チームはこのトランザクションデータに関連した、I/O とメモリーの最適化を実装できます。たとえば、Undo データはディスクに書き込まれ、その上まれにしか使用されないため (クラッシュリカバリの場合にのみ)、ファイルシステムのメモリーキャッシュに保持しておく必要がなく、その結果、より多くのシステムメモリーを InnoDBバッファープール に割り当てることができます。

InnoDB システムのテーブルスペースをハードドライブに保持し、テーブルごとのテーブルスペースを SSD に移動するという、典型的な SSD ベストプラクティスは、Undo 情報を個々のテーブルスペースファイルに移動することで役に立ちます。

内部情報

物理的なテーブルスペースファイルの名前は undoN です。ここで、N はスペース ID (頭のゼロを含む) です。

現在、個々の Undo テーブルスペースを含む MySQL インスタンスは、MySQL 5.5 や 5.1 などの以前のリリースにはダウングレードできません。

14.5.7 InnoDB ログファイルの数またはサイズの変更、および InnoDB テーブルスペースのサイズの変更

このセクションでは、InnoDBRedo ログファイルの数またはサイズを変更する方法、および InnoDBシステムテーブルスペースのサイズを増加または減少する方法について説明します。

InnoDB ログファイルの数またはサイズの変更

MySQL 5.6.7 以前で InnoDB の Redo ログファイルの数またはサイズを変更するには、次の手順を実行します。

  1. innodb_fast_shutdown が 2 に設定されている場合は、innodb_fast_shutdown を 1 に設定します。

    mysql> SET GLOBAL innodb_fast_shutdown = 1;
  2. innodb_fast_shutdown が 2 に設定されていないことを確認したあとに、MySQL サーバーを停止し、エラーなしでシャットダウンされること (ログ内に未処理のトランザクションに関する情報が存在しないこと) を確認します。

  3. シャットダウン中に何か問題が発生して、テーブルスペースをリカバリするために古いログファイルが必要となる場合に備えて、それらのログファイルを安全な場所にコピーします。

  4. ログファイルディレクトリから古いログファイルを削除します。

  5. my.cnf を編集して、ログファイルの構成を変更します。

  6. MySQL を再起動します。mysqld によって、起動時に InnoDB ログファイルが存在しないことが表示され、新しいログファイルが作成されます。

MySQL 5.6.8 の時点では、InnoDB ログファイルの数またはサイズを変更する際に、innodb_fast_shutdown 設定が関連しなくなりました。さらに、古いログファイルを削除する必要もなくなりました。ただし、バックアップとして古いログファイルを安全な場所にコピーすることはあります。InnoDB のログファイルの数またはサイズを変更するには、次の手順を実行します。

  1. MySQL サーバーを停止し、エラーなしでシャットダウンされることを確認します。

  2. my.cnf を編集して、ログファイルの構成を変更します。ログファイルのサイズを変更するには、innodb_log_file_size を構成します。ログファイルの数を多くするには、innodb_log_files_in_group を構成します。

  3. MySQL サーバーを再起動します。

InnoDBinnodb_log_file_size が Redo ログファイルのサイズと異なることが検出された場合は、ログチェックポイントが書き込まれ、古いログファイルが閉じられてから削除され、リクエストされたサイズで新しいファイルが作成され、その新しいログファイルが開かれます。

InnoDB テーブルスペースのサイズの増加

InnoDB システムテーブルスペースのサイズを大きくするもっとも簡単な方法は、最初から自動拡張として構成することです。テーブルスペース定義内の最後のデータファイルに autoextend 属性を指定します。これにより、InnoDB が領域を使い果たすと、そのファイルのサイズが自動的に 8M バイトずつ増加します。innodb_autoextend_increment システム変数の値を設定すると、増分のサイズを変更できます。このサイズは、M バイト単位で測定されます。

別のデータファイルを追加すると、システムテーブルスペースを定義された量だけ拡大できます。

  1. MySQL サーバーをシャットダウンします。

  2. 以前の最後のデータファイルが autoextend というキーワードを使用して定義されている場合は、実際に増加した大きさに基づいて、固定サイズが使用されるようにその定義を変更します。データファイルのサイズをチェックし、それを 1024 × 1024 バイト (= 1M バイト) にもっとも近い倍数に丸め、この丸められたサイズを innodb_data_file_path に明示的に指定します。

  3. 新しいデータファイルを innodb_data_file_path の末尾に追加します。これにより、オプションでそのファイルが自動拡張になります。innodb_data_file_path で自動拡張として指定できるのは、最後のデータファイルのみです。

  4. MySQL サーバーを再起動します。

たとえば、このテーブルスペースには、ibdata1 という 1 つの自動拡張データファイルしか存在しません。

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:10M:autoextend

このデータファイルが、時間をかけて 988M バイトまで増加したと仮定します。次に、固定サイズが使用されるように元のデータファイルを変更し、新しい自動拡張データファイルを追加したあとの構成行を示します。

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend

新しいデータファイルをシステムテーブルスペース構成に追加する際に、そのファイル名が既存のファイルを参照していないことを確認してください。InnoDB は、サーバーの起動時にファイルを作成し、初期化します。

InnoDB テーブルスペースのサイズの減少

現在は、システムテーブルスペースからデータファイルを削除できません。システムテーブルスペースのサイズを小さくするには、次の手順を使用します。

  1. mysqldump を使用して、MySQL データベース内に配置されている InnoDB テーブルを含む、すべての InnoDB テーブルをダンプします。5.6 の時点では、MySQL データベース内に 5 つの InnoDB テーブルが含まれています。

    mysql> select table_name from information_schema.tables where table_schema='mysql' and engine='InnoDB';
    +----------------------+
    | table_name |
    +----------------------+
    | innodb_index_stats |
    | innodb_table_stats |
    | slave_master_info |
    | slave_relay_log_info |
    | slave_worker_info |
    +----------------------+
    5 rows in set (0.00 sec) 
  2. サーバーを停止します。

  3. ibdata および ib_log ファイルを含む、すべての既存のテーブルスペースファイル (*.ibd) を削除します。MySQL データベース内に配置されているテーブルの *.ibd ファイルも忘れずに削除してください。

  4. InnoDB テーブルのすべての .frm ファイルを削除します。

  5. 新しいテーブルスペースを構成します。

  6. サーバーを再起動します。

  7. ダンプファイルをインポートします。

注記

データベースで InnoDB エンジンのみが使用されている場合は、すべてのデータベースをダンプし、サーバーを停止し、すべてのデータベースおよび InnoDB のログファイルを削除し、サーバーを再起動し、ダンプファイルをインポートした方が簡単な可能性があります。

14.5.8 共有テーブルスペースでの RAW ディスクパーティションの使用

InnoDBシステムテーブルスペースでは、データファイルとして RAW ディスクパーティションを使用できます。この方法を使用すると、ファイルシステムのオーバーヘッドが発生せずに、Windows 上および一部の Linux と Unix 上でバッファーに入れられない I/O が有効になります。RAW パーティションを使用する場合と使用しない場合でテストを実行して、この変更によって実際にシステム上のパフォーマンスが改善されるかどうかを確認します。

RAW ディスクパーティションを使用する場合は、MySQL サーバーを実行しているユーザー ID がそのパーティションに対する読み取り権限および書き込み権限を持っていることを確認します。たとえば、mysql ユーザーとしてサーバーを実行する場合は、そのパーティションが mysql によって読み取り可能および書き込み可能である必要があります。--memlock オプションを付けてサーバーを実行する場合は、サーバーを root として実行する必要があるため、パーティションが root によって読み取り可能および書き込み可能である必要があります。

次で説明する手順には、オプションファイルの変更が伴います。追加情報については、セクション4.2.6「オプションファイルの使用」を参照してください。

Linux および Unix システムでの RAW ディスクパーティションの割り当て

  1. 新しいデータファイルを作成する際は、innodb_data_file_path オプションのデータファイルサイズの直後に、newraw というキーワードを指定します。パーティションは、少なくとも指定したサイズと同じである必要があります。ディスク指定の 1M バイトは通常 1,000,000 バイトを意味するのに対して、InnoDB 内の 1M バイトは 1024 × 1024 バイトであることに注意してください。

    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw
  2. サーバーを再起動します。InnoDB によって newraw キーワードが認識され、新しいパーティションが初期化されます。ただし、まだ InnoDB テーブルを作成したり変更したりしないでください。そうしなければ、サーバーを次に再起動したときに InnoDB によってパーティションが再初期化され、変更がすべて失われます。(安全策として、InnoDB では、newraw を含むパーティションが指定されたときにユーザーがデータを更新することが回避されます。)

  3. InnoDB によって新しいパーティションが初期化されたら、サーバーを停止し、データファイルの指定で newrawraw に変更します。

    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=/dev/hdd1:3Graw;/dev/hdd2:2Graw
  4. サーバーを再起動します。これにより、InnoDB で変更を行うことが許可されます。

Windows での RAW ディスクパーティションの割り当て

Windows システムでは、Linux および Unix システムで説明したものと同じ手順および付随するガイドラインが適用されます。ただし、Windows では innodb_data_file_path の設定がわずかに異なります。

  1. 新しいデータファイルを作成する際は、innodb_data_file_path オプションのデータファイルサイズの直後に、newraw というキーワードを指定します。

    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=//./D::10Gnewraw

    //./ は、物理ドライブにアクセスするための Windows の構文 \\.\ に対応しています。前述の例では、D: がパーティションのドライブ文字です。

  2. サーバーを再起動します。InnoDB によって newraw キーワードが認識され、新しいパーティションが初期化されます。

  3. InnoDB によって新しいパーティションが初期化されたら、サーバーを停止し、データファイルの指定で newrawraw に変更します。

    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=//./D::10Graw
  4. サーバーを再起動します。これにより、InnoDB で変更を行うことが許可されます。

14.6 InnoDB テーブルの管理

14.6.1 InnoDB テーブルの作成

InnoDB テーブルを作成するには、特別な句を付けずに CREATE TABLE ステートメントを使用します。以前は、ENGINE=InnoDB 句が必要でしたが、InnoDB がデフォルトのストレージエンジンとなったため必要なくなりました。(デフォルトのストレージエンジンが MyISAM である MySQL 5.1 以前が実行されているサーバー上で、mysqldump またはレプリケーションを使用して CREATE TABLE ステートメントを再現する予定がある場合は、その句を引き続き使用できます。)

-- Default storage engine = InnoDB.
CREATE TABLE t1 (a INT, b CHAR (20), PRIMARY KEY (a));
-- Backward-compatible with older MySQL.
CREATE TABLE t2 (a INT, b CHAR (20), PRIMARY KEY (a)) ENGINE=InnoDB;

innodb_file_per_table の設定に応じて、InnoDB ではシステムテーブルスペース内またはテーブルごとの別個のテーブルスペース (.ibd ファイルで表されます) 内に、各テーブルおよび関連付けられた主キーインデックスが作成されます。MySQL では、MySQL データベースディレクトリの下にある test ディレクトリ内に、t1.frm および t2.frm ファイルが作成されます。内部的に、InnoDB 独自のデータディクショナリにテーブルのエントリが追加されます。このエントリには、データベース名が含まれます。たとえば、t1 テーブルが作成されるデータベースが test である場合、エントリは 'test/t1' となります。つまり、ほかのいくつかのデータベースに同じ名前 t1 のテーブルを作成でき、InnoDB 内部でテーブル名の競合は発生しません。

これらのテーブルのプロパティーを表示するには、SHOW TABLE STATUS ステートメントを発行します。

SHOW TABLE STATUS FROM test LIKE 't%' \G;

ステータスの出力には、これらの 1 番目のテーブルの行フォーマットプロパティーが「Compact」であることが表示されます。この設定は基本的な実験には適していますが、もっとも強力な InnoDB のパフォーマンス機能を活用するには、すぐに「Dynamic」「Compressed」などのその他の行フォーマットの使用に進んでください。これらの値を使用するには、最初に少しの設定が必要です。

set global innodb_file_per_table=1;
set global innodb_file_format=barracuda;
CREATE TABLE t3 (a INT, b CHAR (20), PRIMARY KEY (a)) row_format=dynamic;
CREATE TABLE t4 (a INT, b CHAR (20), PRIMARY KEY (a)) row_format=compressed;

必ず、InnoDB テーブルごとに主キーを設定し、次のようなカラム (複数の場合あり) を指定してください。

  • もっとも重要なクエリーで参照される。

  • ブランクのままになっていない。

  • 重複する値がない。

  • 挿入後に値が変更されるとしても、きわめてまれである。

たとえば、人に関する情報を含むテーブルでは、複数の人が同じ名前を持つ可能性もあり、名字をブランクにしたり、名前を変更したりする人もいるため、(名、姓) 上には主キーを作成しません。制約が非常に多く、主キーとして使用する明確なカラムセットがないことも多い場合には、主キーの全部または一部として機能する数値 ID の新しいカラムを作成してください。行が挿入されると自動的に昇順の値が入力されるように、自動インクリメントカラムを宣言できます。

-- The value of ID can act like a pointer between related items in different tables.
CREATE TABLE t5 (id INT AUTO_INCREMENT, b CHAR (20), PRIMARY KEY (id));
-- The primary key can consist of more than one column. Any autoinc column must come first.
CREATE TABLE t6 (id INT AUTO_INCREMENT, a INT, b CHAR (20), PRIMARY KEY (id,a));

主キーを定義しなくてもテーブルは正常に機能しますが、主キーは多くのパフォーマンス要素に関連し、大きなテーブルや頻繁に使用されるテーブルにとって重要な設計要素です。常に CREATE TABLE ステートメントで指定することを習慣にしてください。(テーブルを作成し、データをロードしてから、ALTER TABLE を実行してあとで主キーを追加する場合の操作は、テーブルの作成時に主キーを定義するよりも大幅に時間がかかります。)

14.6.2 別のマシンへの InnoDB テーブルの移動またはコピー

このセクションでは、一部またはすべての InnoDB テーブルを別のサーバーに移動またはコピーするための方法について説明します。たとえば、MySQL インスタンス全体をより大規模で高速なサーバーに移動したり、MySQL インスタンス全体のクローンを新しいレプリケーションスレーブサーバーに作成したり、アプリケーションを開発およびテストするために各テーブルを別のサーバーにコピーしたり、レポートを生成するためにデータウェアハウスサーバーにコピーしたりする場合があります。

InnoDB テーブルを移動またはコピーするための方法は、次のとおりです。

小文字の名前を使用したプラットフォーム間の移動またはコピー

Windows 上の InnoDB では常に、データベース名およびテーブル名が内部的に小文字で格納されます。バイナリ形式のデータベースを Unix から Windows に、または Windows から Unix に移動するには、すべてのデータベースおよびテーブルを小文字の名前を使用して作成します。これを実現する便利な方法は、データベースやテーブルを作成する前に、my.cnf または my.ini ファイルの [mysqld] セクションに次の行を追加することです。

[mysqld]
lower_case_table_names=1

トランスポータブルテーブルスペース

MySQL 5.6.6 で導入されたトランスポータブルテーブルスペース機能では、あるサーバーインスタンスから別のサーバーインスタンスにコピーするように InnoDB を準備する際に、FLUSH TABLES ... FOR EXPORT が使用されます。この機能を使用するには、各 InnoDB テーブルが独自のテーブルスペースを持つように、innodb_file_per_tableON に設定した状態で InnoDB テーブルを作成する必要があります。使用法については、セクション14.5.5「テーブルスペースの別のサーバーへのコピー (トランスポータブルテーブルスペース)」を参照してください。

MySQL Enterprise Backup

MySQL Enterprise Backup 製品を使用すると、実行中の MySQL データベース (InnoDB および MyISAM テーブルを含む) を、データベースの整合性のあるスナップショットを生成しながら、操作の中断を最小限に抑えてバックアップできます。MySQL Enterprise Backup が InnoDB テーブルをコピーしている間は、InnoDB テーブルと MyISAM テーブルの両方に対する読み取りと書き込みを続行できます。MyISAM およびその他の InnoDB 以外のテーブルのコピー中は、これらのテーブルに対する (書き込みではなく) 読み取りが許可されます。さらに、MySQL Enterprise Backup では、圧縮バックアップファイルを作成したり、InnoDB テーブルのサブセットをバックアップしたりすることもできます。MySQL のバイナリログと組み合わせると、ポイントインタイムリカバリを実行できます。MySQL Enterprise Backup は、MySQL Enterprise サブスクリプションの一部として含まれています。

MySQL Enterprise Backup についての詳細は、セクション25.2「MySQL Enterprise Backup」を参照してください。

データファイルのコピー (コールドバックアップ方式)

単に、セクション14.16「InnoDB のバックアップとリカバリ」の「コールドバックアップ」で一覧表示した関連ファイルをすべてコピーするだけで、InnoDB データベースを移動できます。

MyISAM データファイルと同様に、InnoDB のデータファイルとログファイルにも、同じ浮動小数点数形式を持つすべてのプラットフォーム上でのバイナリ互換性があります。浮動小数点形式が異なっている場合でも、テーブル内で FLOAT または DOUBLE データ型を使用していなければ、手順は同じです。単に、関連するファイルをコピーするだけです。

.ibd ファイルの移植性に関する考慮事項

.ibd ファイルを移動またはコピーする際は、ソースシステムと宛先システムでデータベースディレクトリ名を同じにする必要があります。データベース名は、InnoDB の共有テーブルスペース内に格納されているテーブル定義に含まれています。テーブルスペースファイル内に格納されているトランザクション ID およびログシーケンス番号も、データベース間で異なります。

あるデータベースから別のデータベースに .ibd ファイルとそれに関連付けられたテーブルを移動するには、RENAME TABLE ステートメントを使用します。

RENAME TABLE db1.tbl_name TO db2.tbl_name;

.ibd ファイルのクリーンなバックアップがある場合は、次のように、そのバックアップが生成された MySQL インストールにリストアできます。

  1. .ibd ファイルをコピーすると、テーブルスペース内に格納されたテーブル ID が変更されるため、それ以降はテーブルの削除または切り捨ては実行されなかったはずです。

  2. 次の ALTER TABLE ステートメントを発行して、現在の .ibd ファイルを削除します。

    ALTER TABLE tbl_name DISCARD TABLESPACE;
  3. バックアップ .ibd ファイルを適切なデータベースディレクトリにコピーします。

  4. 次の ALTER TABLE ステートメントを発行して、このテーブルで新しい .ibd ファイルを使用するように InnoDB に指示します。

    ALTER TABLE tbl_name IMPORT TABLESPACE;
    注記

    ALTER TABLE ... IMPORT TABLESPACE 機能は、インポートされたデータに対して外部キー制約を課しません。

このコンテキストでは、クリーンな.ibd バックアップファイルとは、次の要件を満たすファイルです。

  • .ibd ファイル内には、トランザクションによってコミットされていない変更はありません。

  • .ibd ファイル内にマージされていない挿入バッファーエントリはありません。

  • パージによって、.ibd ファイルから削除マークが付けられたすべてのインデックスレコードが削除されました。

  • mysqld によって、.ibd ファイルの変更されたページがすべてバッファープールからファイルにフラッシュされました。

次の方法を使用すると、クリーンなバックアップ .ibd ファイルを作成できます。

  1. mysqld サーバーからのすべてのアクティビティーを停止し、すべてのトランザクションをコミットします。

  2. SHOW ENGINE INNODB STATUS でデータベース内にアクティブなトランザクションがないことが表示され、InnoDB のメインスレッドステータスが「Waiting for server activity」になるまで待機します。これにより、.ibd ファイルのコピーを作成できるようになります。

.ibd ファイルのクリーンなコピーを作成するためのもう 1 つの方法は、MySQL Enterprise Backup 製品を使用することです。

  1. MySQL Enterprise Backup を使用して、InnoDB インストールをバックアップします。

  2. 2 番目の mysqld サーバーをバックアップ上で起動します。そのサーバーで、バックアップ内の .ibd ファイルがクリーンアップされます。

エクスポートとインポート (mysqldump)

mysqldump を使用すると、あるマシン上でテーブルをダンプしてから、別のマシン上でそのダンプファイルをインポートできます。この方式を使用すれば、形式が異なっているかどうかや、テーブルに浮動小数点データが含まれているかどうかは関係ありません。

インポートトランザクションで生成される巨大なロールバックセグメント用の領域がテーブルスペースに十分にあると仮定すれば、この方式のパフォーマンスを向上させる方法の 1 つは、データのインポート時に自動コミットモードをオフにすることです。コミットは、テーブル全体またはテーブルのセグメントをインポートしたあとでのみ行なってください。

14.6.3 トランザクションを使用した DML 操作のグループ化

デフォルトでは、MySQL サーバーへの接続は、自動コミットモードが有効になっている状態で開始されるため、SQL ステートメントは実行するたびに自動的にコミットされます。一連の DML ステートメントを発行し、すべてまとめてコミットまたはロールバックすることが標準操作となっているほかのデータベースシステムの使用経験がある場合は、この操作モードに馴染みがないかもしれません。

複数ステートメントのトランザクションを使用するには、SQL ステートメント SET autocommit = 0 を使用して自動コミットをオフにして、必要に応じて COMMIT または ROLLBACK を使用して各トランザクションを終了します。自動コミットをオンのままにするには、START TRANSACTION を使用して各トランザクションを開始し、COMMIT または ROLLBACK を使用して終了します。次の例は 2 つのトランザクションを表しています。1 番目はコミットされ、2 番目はロールバックされています。

shell> mysql testmysql> CREATE TABLE customer (a INT, b CHAR (20), INDEX (a));Query OK, 0 rows affected (0.00 sec)
mysql> -- Do a transaction with autocommit turned on.mysql> START TRANSACTION;Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO customer VALUES (10, 'Heikki');Query OK, 1 row affected (0.00 sec)
mysql> COMMIT;Query OK, 0 rows affected (0.00 sec)
mysql> -- Do another transaction with autocommit turned off.mysql> SET autocommit=0;Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO customer VALUES (15, 'John');Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO customer VALUES (20, 'Paul');Query OK, 1 row affected (0.00 sec)
mysql> DELETE FROM customer WHERE b = 'Heikki';Query OK, 1 row affected (0.00 sec)
mysql> -- Now we undo those last 2 inserts and the delete.mysql> ROLLBACK;Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM customer;+------+--------+
| a | b |
+------+--------+
| 10 | Heikki |
+------+--------+
1 row in set (0.00 sec)
mysql>

クライアント側言語でのトランザクション

PHP、Perl DBI、JDBC、ODBC などの API または MySQL の標準 C 呼び出しインタフェースでは、COMMIT などのトランザクション制御ステートメントを SELECTINSERT などのその他の SQL ステートメントと同様の文字列として、MySQL サーバーに送信できます。一部の API では、別個の特別なトランザクションコミットおよびロールバックの関数やメソッドも提供されています。

14.6.4 MyISAM から InnoDB へのテーブルの変換

信頼性および拡張性を改善するために、既存のテーブルを使用するアプリケーションを InnoDB に変換する場合は、次のガイドラインおよびヒントを使用します。このセクションでは、このようなテーブルの大部分が当初は、以前のデフォルトの MyISAM であったことが前提となっています。

MyISAM のメモリー使用量の減少、InnoDB のメモリー使用量の増加

MyISAM テーブルから移行するときに、結果をキャッシュする際に必要でなくなったメモリーが解放されるように、key_buffer_size 構成オプションの値を小さくします。InnoDB テーブル用のキャッシュメモリー割り当てと同様の役割を担う innodb_buffer_pool_size 構成オプションの値を大きくします。InnoDBバッファープールには、テーブルデータとインデックスデータの両方がキャッシュされるため、クエリーの検索速度を上げることと、再使用するためにクエリー結果をメモリー内に保持することの 2 つ役割があります。

  • このオプションには、できるかぎり多くのメモリー (多くの場合、最大でサーバー上の物理メモリーの 80% まで) を割り当てます。

  • オペレーティングシステムでその他のプロセス用のメモリーが不足し、スワップが発生し始めた場合は、innodb_buffer_pool_size の値を小さくします。スワップとは、キャッシュメモリーの利点が大幅に減少するような負荷の高い操作です。

  • innodb_buffer_pool_size 値が数ギガバイト以上である場合は、innodb_buffer_pool_instances の値を大きくすることを検討してください。これを行うと、同時に数多くの接続がキャッシュにデータを読み込む高負荷のサーバーで役立ちます。

  • 高負荷のサーバーでは、クエリーキャッシュをオフにしてベンチマークを実行します。InnoDB のバッファープールでも同様の利点が得られるため、クエリーキャッシュを使用すると、不必要にメモリーが停止する可能性があります。

長すぎるまたは短すぎるトランザクションの監視

MyISAM テーブルではトランザクションがサポートされていないため、autocommit 構成オプションと、COMMIT および ROLLBACK ステートメントに多くの注意が払われていない可能性があります。これらのキーワードは、複数のセッションが並列して InnoDB テーブルの読み取りおよび書き込みを行うことを許可する際に重要となります。これにより、書き込み負荷の高いワークロードで十分な拡張性の利点が得られます。

トランザクションが開いている間は、トランザクションの開始時に見られるようなデータのスナップショットがシステムで保持されます。これにより、未処理のトランザクションが動作し続けている間に、システムで数百万行の挿入、更新、および削除が行われると、相当なオーバーヘッドが発生する可能性があります。そのため、動作時間が長すぎるトランザクションは回避するように注意してください。

  • インタラクティブな実験で mysql セッションを使用している場合は、完了後に必ず、(変更を完了させる場合は) COMMIT、または (変更を取り消す場合は) ROLLBACK を実行します。誤ってトランザクションが長時間開いたままになることを回避するには、インタラクティブなセッションを長時間開いたままにせず、閉じてください。

  • アプリケーション内の任意のエラーハンドラでも、不完全な変更の ROLLBACK が実行されるか、完了した変更の COMMIT が実行されることを確認します。

  • INSERTUPDATE、および DELETE 操作は、ほとんどの変更は正常にコミットされ、ロールバックはまれにしか発生しないという見込みで、COMMIT よりも前に InnoDB テーブルに書き込まれるため、ROLLBACK は比較的負荷の高い操作です。大量のデータを使用して実験する際は、多数の行に変更を加えてから、それらの変更をロールバックすることは回避してください。

  • 一連の INSERT ステートメントを使用して大量のデータをロードする際は、トランザクションが数時間存続することを回避するために、定期的に結果の COMMIT を実行します。データウェアハウスでの一般的なロード操作では、何か問題が発生した場合に、ユーザーは ROLLBACK を行うのではなく、TRUNCATE TABLE を実行し、最初からやり直します。

前述のヒントを使用すると、長すぎるトランザクション中に無駄になる可能性のあるメモリーおよびディスク容量を節約できます。トランザクションが本来よりも短い場合は、過剰な I/O が問題となります。MySQL では、COMMIT が実行されるたびに、各変更が安全にディスクに記録されていることが確認されます。これには、多少の I/O が伴います。

  • InnoDB テーブル上のほとんどの操作では、autocommit=0 の設定を使用するようにしてください。効率性の観点から見ると、これにより、多数の連続した INSERTUPDATE、または DELETE ステートメントを発行したときの不要な I/O が回避されます。安全性の観点から見ると、これにより、mysql コマンド行またはアプリケーションの例外ハンドラに誤りがあった場合に、ROLLBACK ステートメントを発行することで、失ったデータや文字化けしたデータをリカバリできます。

  • InnoDB テーブルに autocommit=1 を設定することが適している状況は、レポートの生成または統計の分析を行うために一連のクエリーを実行するときです。このような状況では、COMMIT または ROLLBACK に関連する I/O ペナルティーが発生せず、InnoDB自動的に読み取り専用のワークロードを最適化できます

  • 関連する一連の変更を行う場合は、最後に 1 回 COMMIT を実行して、これらのすべての変更を一度に完了させます。たとえば、情報の関連部分を複数のテーブルに挿入する場合は、すべての変更を行なったあとに、COMMIT を 1 回実行します。また、連続する多数の INSERT ステートメントを実行する場合は、すべてのデータがロードされたあとに、COMMIT を 1 回実行します。何百万もの INSERT ステートメントを実行する場合は、一万または一千レコードごとに COMMIT を発行することで、巨大なトランザクションを分割することがあります。

  • SELECT ステートメントでもトランザクションが開かれるため、インタラクティブな mysql セッションで一部のレポートを実行したり、クエリーをデバッグしたりしたあとは、COMMIT を発行するか、または mysql セッションを閉じます。

デッドロックを心配しすぎないこと

MySQL のエラーログまたは SHOW ENGINE INNODB STATUS の出力に、デッドロックに言及する警告メッセージが表示されることがあります。デッドロックは、恐ろしい響きの名前にもかかわらず、InnoDB テーブルにとっては重大な問題でなく、修正アクションは何も必要ありません。2 つのトランザクションが複数のテーブルを変更し、そのテーブルに別々の順序でアクセスし始めると、各トランザクションが相互に待機し合って、どちらも処理できない状態に達する可能性があります。すぐに MySQL によって、この状況が検出され、小さい方のトランザクションが取り消され (ロールバックされ)、他方が処理できるようになります。

アプリケーションには、このように強制的に取り消されたトランザクションを再開するためのエラー処理ロジックが必要です。以前と同じ SQL ステートメントを再発行するときは、元のタイミングの問題は適用されません。他方のトランザクションがすでに完了したため一方を処理できるか、他方のトランザクションがまだ処理中で、これが完了するまで一方が待機しているかのいずれかです。

デッドロックの警告が常に発生する場合は、アプリケーションコードを再確認して、一貫性のある方法で SQL 操作を再指示したり、トランザクションを短くしたりすることがあります。innodb_print_all_deadlocks オプションを有効にしてテストすれば、SHOW ENGINE INNODB STATUS 出力の最後の警告だけでなく、MySQL のエラーログにもすべてのデッドロックの警告を表示できます。

ストレージレイアウトの計画

InnoDB テーブルから最高のパフォーマンスを引き出すために、ストレージレイアウトに関連する数多くのパラメータを調整できます。

頻繁にアクセスされ、重要なデータが保持されている大きな MyISAM テーブルを変換する際は、innodb_file_per_tableinnodb_file_formatinnodb_page_size 構成オプション、および CREATE TABLE ステートメントの ROW_FORMATKEY_BLOCK_SIZEを調査および検討してください。

初期の実験時に、もっとも重要となる設定は innodb_file_per_table です。新しい InnoDB テーブルを作成する前に、このオプションを有効にすると、InnoDBシステムテーブルスペースファイルを使用して、すべての InnoDB データ用のディスク領域が永続的に割り当てられなくなります。innodb_file_per_table を有効にすると、DROP TABLE および TRUNCATE TABLE を発行することで、要求どおりにディスク領域が解放されます。

既存テーブルの変換

InnoDB を使用するように InnoDB 以外のテーブルを変換するには、ALTER TABLE を使用します。

ALTER TABLE table_name ENGINE=InnoDB;
重要

mysql データベース内の MySQL システムテーブル (userhost など) を InnoDB 型に変換しないでください。これはサポートされていない操作です。システムテーブルの型は、必ず MyISAM にする必要があります。

テーブル構造のクローニング

古いテーブルと新しいテーブルを切り替える前に並列してテストする際に、ALTER TABLE 変換を行うのではなく、MyISAM テーブルのクローンである InnoDB テーブルを作成することがあります。

同じカラムとインデックスの定義を持つ空の InnoDB テーブルを作成します。show create table table_name\G を使用して、使用される完全な CREATE TABLE ステートメントを表示します。ENGINE 句を ENGINE=INNODB に変更します。

既存データの転送

前のセクションで示したように、作成された空の InnoDB テーブルに大量のデータを転送するには、INSERT INTO innodb_table SELECT * FROM myisam_table ORDER BY primary_key_columns を使用して行を挿入します。

データを挿入したあとに、InnoDB テーブル用のインデックスを作成することもできます。従来、新しいセカンダリインデックスを作成することは、InnoDB にとって低速な操作でしたが、現在は、インデックスの作成ステップで比較的小さいオーバーヘッドでデータがロードされたあとに、インデックスを作成できるようになりました。

副キー上に UNIQUE 制約がある場合は、インポート操作中に一意性チェックを一時的にオフにすることで、テーブルインポートの速度を上げることができます。

SET unique_checks=0;... import operation ...SET unique_checks=1;

大きいテーブルの場合、InnoDB はその挿入バッファーを使用して、一括してセカンダリインデックスレコードを書き込むことができるため、これにより、大量のディスク I/O が節約されます。データに重複キーが含まれないようにします。unique_checks では、ストレージエンジンが重複キーを無視することが許可されていますが、必須ではありません。

挿入プロセスをより適切に制御するために、大きなテーブルを分割して挿入することがあります。

INSERT INTO newtable SELECT * FROM oldtable WHERE yourkey > something AND yourkey <= somethingelse;

すべてのレコードが挿入されたあとに、テーブルの名前を変更できます。

ディスク I/O を削減するには、大きなテーブルの変換時に、最大で物理メモリーの 80% まで InnoDB バッファープールのサイズを大きくします。InnoDB ログファイルのサイズを大きくすることもできます。

ストレージ要件

すでに説明したように、この時点で、すでに innodb_file_per_table オプションが有効になっている必要があります。これにより、InnoDB テーブル内にデータの複数のコピーを一時的に作成している場合は、あとで不要なテーブルを削除することで、そのディスク領域をすべてリカバリできます。

MyISAM テーブルを直接変換するのか、クローンの InnoDB テーブルを作成するのかには関係なく、プロセス中に古いテーブルと新しいテーブルの両方を保持するのに十分なディスク領域があることを確認します。InnoDB テーブルには、MyISAM テーブルよりも多くのディスク領域が必要です。ALTER TABLE 操作によって領域が使い果たされると、ロールバックが開始されますが、ディスクバウンドの場合は、数時間かかる可能性があります。挿入の場合、InnoDB はバッチ内のインデックスにセカンダリインデックスレコードをマージする際に、挿入バッファーを使用します。これにより、大量のディスク I/O が節約されます。ロールバックでは、このようなメカニズムは使用されません。ロールバックは挿入よりも、30 倍長い時間がかかる可能性があります。

ランナウェイロールバックの場合は、データベースに貴重なデータがなければ、何百万ものディスク I/O 操作が完了するまで待機するのではなく、データベースプロセスを強制終了することをお勧めします。完全な手順については、セクション14.19.2「InnoDB のリカバリの強制的な実行」を参照してください。

テーブルごとの主キーの慎重な選択

PRIMARY KEY 句は、MySQL クエリーのパフォーマンスや、テーブルおよびインデックス用の領域使用量に影響を与える重要な要素です。おそらく、金融機関に電話をかけ、口座番号を求められた経験があるでしょう。その番号を持っていない場合は、自分自身を一意に識別するために、多種多様な情報が求められます。主キーは、テーブル内の情報を問い合わせたり、変更したりする際に、すぐに仕事に取りかかるための一意の口座番号のようなものです。テーブル内のすべて行が主キー値を持っている必要があり、2 つの行が同じ主キー値を持つことはできません。

次に、主キーに関するいくつかのガイドラインに続き、さらに詳細な説明を示します。

  • テーブルごとに PRIMARY KEY を宣言します。一般に、単一の行を検索するときに参照される WHERE 句内のカラムの中で、もっとも重要なものです。

  • あとで ALTER TABLE ステートメントを使用して追加するのではなく、元の CREATE TABLE ステートメントで PRIMARY KEY 句を宣言します。

  • カラムとそのデータ型は慎重に選択してください。文字または文字列のカラムよりも、数値のカラムを優先してください。

  • 別の安定していて、一意で、非 NULL で、数値のカラムが使用できない場合は、自動インクリメントカラムを使用することを検討してください。

  • 主キーカラムの値が変更されたかどうかが疑わしい場合にも、自動インクリメントは適切な選択です。主キーカラムの値を変更することは、負荷の高い操作であり、テーブル内および各セカンダリインデックス内でデータの再編成が伴う可能性があります。

主キーがまだ存在しないテーブルには、追加することを検討してください。計画されたテーブルの最大サイズに基づいて、現実的な最小の数値型を使用します。これにより、各行をわずかにコンパクトにすることができ、大きなテーブル用に相当な領域を節約できます。主キー値は、セカンダリインデックスが入力されるたびに繰り返されるため、テーブルが任意のセカンダリインデックスを持っている場合は、領域の節約も倍増します。小さな主キーを使用すると、ディスク上のデータサイズが削減されることに加えて、より多くのデータをバッファープール内に収容できるため、すべての種類の操作の速度が上がり、並列性が改善されます。

すでにテーブルの多少長いカラム (VARCHAR など) 上に主キーが存在する場合は、そのカラムがクエリーで参照されていなくても、新しい符号なし AUTO_INCREMENT カラムを追加し、主キーをそのカラムに切り替えることを検討してください。このような設計の変更によって、セカンダリインデックス内の相当な領域を節約できます。以前の主キーカラムを UNIQUE NOT NULL として指定すると、PRIMARY KEY 句と同じ制約を強制的に適用できます (つまり、これらのすべてのカラムにわたって重複する値や NULL 値を回避できます)。

関連する情報を複数のテーブルに分散させる場合は、一般に各テーブルで、その主キー用に同じカラムが使用されます。たとえば、人事部のデータベースには複数のテーブルが含まれ、各テーブルには従業員番号の主キーが含まれている場合があります。営業部のデータベースには、顧客番号の主キーを含むテーブルや、注文番号の主キーを含むテーブルが含まれている場合があります。主キーを使用した検索は非常に高速であるため、このようなテーブルには効率的な結合クエリーを構築できます。

PRIMARY KEY 句を完全に削除すると、MySQL によって自動的に非表示の主キーが作成されます。これは、必要以上に長くなる可能性のある 6 バイトの値であるため、領域が無駄になります。これは非表示であるため、クエリーで参照できません。

アプリケーションのパフォーマンスに関する考慮事項

InnoDB の追加の信頼性および拡張性機能を使用するには、同等の MyISAM テーブルよりも多くのディスクストレージが必要となります。領域の使用率を改善し、結果セットを処理する際の I/O およびメモリーの消費を削減し、インデックス検索を効率的に使用するクエリーの最適化計画を改善するために、カラムおよびインデックスの定義をわずかに変更することがあります。

主キーに数値の ID カラムを設定する場合 (特に、結合クエリーの場合) は、その値を使用して、その他の任意のテーブル内の関連する値と相互参照します。たとえば、入力として国名を受け入れ、同じ名前を検索するクエリーを実行するのではなく、国 ID を確認するための検索を 1 回実行してから、複数のテーブルにわたって関連情報を検索するための別のクエリー (または 1 回の結合クエリー) を実行します。顧客番号またはカタログ項目番号を数字の文字列として格納すると、数バイトを使い果たす可能性があるため、その代わりに、格納およびクエリー用に数値の ID に変換します。4 バイトの符号なし INT カラムでは、40 億を超える項目 (アメリカ合衆国での billion の意味: 10 億) にインデックスを付けることができます。さまざまな整数型の範囲については、セクション11.2.1「整数型 (真数値) - INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT」を参照してください。

InnoDB テーブルに関連付けられたファイルの理解

InnoDB ファイルを使用する際は、MyISAM ファイルよりも多くの注意および計画が必要となります。

  • InnoDBシステムテーブルスペースを表す ibdata ファイルは削除しないでください。

  • あるサーバーから別のサーバーに InnoDB テーブルをコピーするには、まず FLUSH TABLES ... FOR EXPORT ステートメントを発行してから、table_name.ibd ファイルとともに table_name.cfg ファイルをコピーする必要があります。

14.6.5 InnoDB での AUTO_INCREMENT 処理

InnoDB では、AUTO_INCREMENT カラムを含むテーブルに行を挿入する SQL ステートメントの拡張性およびパフォーマンスが大幅に改善される最適化が提供されています。InnoDB テーブルで AUTO_INCREMENT メカニズムを使用するには、テーブルで最大カラム値を取得するインデックス SELECT MAX(ai_col) ルックアップと同等の操作を実行できるように、AUTO_INCREMENT カラム ai_col をインデックスの一部として定義する必要があります。一般に、これはカラムをどこかのテーブルインデックスの 1 番目のカラムにすることで実現されます。

このセクションでは、InnoDB の自動インクリメントロックの元の (従来の) 実装に関する背景情報を提供し、構成可能なロックメカニズムについて説明し、このメカニズムを構成するためのパラメータを示し、その動作やレプリケーションとの相互作用について説明します。

14.6.5.1 従来の InnoDB の自動インクリメントロック

InnoDB の自動インクリメント処理の元の実装では、ステートメントベースレプリケーションや特定のリカバリシナリオでバイナリログを使用すると発生する問題を回避するために、次のような方針が使用されています。

InnoDB テーブルに AUTO_INCREMENT カラムを指定すると、InnoDB データディクショナリ内のテーブルハンドルに、カラムに新しい値を割り当てる際に使用される自動インクリメントカウンタと呼ばれる特別なカウンタが含まれます。このカウンタは、ディスク上には格納されず、メインメモリー内にのみ格納されます。

InnoDB では、ai_col という名前の AUTO_INCREMENT カラムを含むテーブル t に自動インクリメントカウンタを初期化するために、次のようなアルゴリズムが使用されます。サーバーの起動のあとで、テーブル t への最初の挿入をするために、InnoDB は次のステートメントと同等なものを実行します。

SELECT MAX(ai_col) FROM t FOR UPDATE;

InnoDB は、ステートメントで取得された値を増分し、それをテーブルのカラムおよび自動インクリメントカウンタに割り当てます。デフォルトでは、値が 1 ずつ増分されます。このデフォルトは、auto_increment_increment 構成の設定でオーバーライドできます。

テーブルが空の場合、InnoDB では値 1 が使用されます。このデフォルトは、auto_increment_offset 構成の設定でオーバーライドできます。

自動インクリメントカウンタが初期化される前に、SHOW TABLE STATUS ステートメントで t テーブルが調査される場合は、InnoDB によって値は初期化されますが、増分されず、後続の挿入で使用するために格納されます。この初期化では、テーブル上で通常の排他ロック読み取りが使用され、そのロックはトランザクションの最後まで存続します。

InnoDB は、新たに作成されたテーブル用に自動インクリメントカウンタを初期化するときと同じ手順に従います。

自動インクリメントカウンタが初期化されたあとに、AUTO_INCREMENT カラムの値を明示的に指定しない場合は、InnoDB によってカウンタが増分され、新しい値がカラムに割り当てられます。カラム値を明示的に指定する行を挿入するときに、その値が現在のカウンタ値よりも大きい場合は、カウンタが指定されたカラム値に設定されます。

ユーザーが INSERTAUTO_INCREMENT カラムに NULL または 0 を指定すると、InnoDB では、値が指定されなかった場合と同様にその行が処理され、新しい値が生成されます。

カラムに負の値を割り当てる場合や、値が指定された整数型に格納できる最大整数よりも大きくなる場合は、自動インクリメントメカニズムの動作が定義されません。

自動インクリメントカウンタにアクセスするときに、InnoDB では、トランザクションの最後までではなく、現在の SQL ステートメントの最後まで存続する特別なテーブルレベルの AUTO-INC ロックが使用されます。AUTO_INCREMENT カラムを含むテーブルへの挿入の並列性を改善するために、特別なロック解放方針が導入されました。それにもかかわらず、2 つのトランザクションが同時に AUTO-INC ロックを同じテーブル上で持つことはできません。これにより、AUTO-INC ロックが長時間保持されると、パフォーマンスが影響を受ける可能性があります。これは、あるテーブルから別のテーブルにすべての行を挿入する INSERT INTO t1 ... SELECT ... FROM t2 などのステートメントの場合に発生する可能性があります。

InnoDB では、サーバーが実行されていれば、インメモリーの自動インクリメントカウンタが使用されます。前に説明したように、サーバーが停止して再起動されると、テーブルへの最初の INSERT 時に、InnoDB によってテーブルごとにカウンタが再初期化されます。

サーバーが再起動されると、CREATE TABLE および ALTER TABLE ステートメントの AUTO_INCREMENT = N テーブルオプションの効果も取り消されます。このオプションを InnoDB テーブルで使用すると、初期のカウンタの値を設定したり、現在のカウンタ値を変更したりできます。

カウンタを使用して数値が生成されたトランザクションをロールバックすると、AUTO_INCREMENT カラムに割り当てられた一連の値でギャップが見つかることがあります。

14.6.5.2 構成可能な InnoDB の自動インクリメントロック

前のセクションで説明したように、InnoDB では AUTO_INCREMENT カラムを含むテーブルへの挿入を行う際に、AUTO-INC ロックと呼ばれる特殊なテーブルレベルロックが使用されます。このロックは通常、指定された一連の INSERT ステートメントに予測可能かつ繰り返し可能な順序で自動インクリメント番号が割り当てられるように、(トランザクションが終了するまでではなく) ステートメントが終了するまで保持されます。

ステートメントベースのレプリケーションの場合、これは、ある SQL ステートメントがスレーブサーバーで複製される際に、自動インクリメントカラムでマスターサーバーと同じ値が使用されることを意味します。複数の INSERT ステートメントの実行結果は決定的であり、マスター上と同じデータがスレーブで再生成されます。複数の INSERT ステートメントによって生成された自動インクリメント値がインターリーブされた場合は、2 つの並列 INSERT ステートメントの結果は非決定的であり、ステートメントベースのレプリケーションを使用してスレーブサーバーに伝搬される際の信頼性も低くなる可能性があります。

この点が明確になるように、次のテーブルを使用する例を考えてみましょう。

CREATE TABLE t1 ( c1 INT(11) NOT NULL AUTO_INCREMENT, c2 VARCHAR(10) DEFAULT NULL, PRIMARY KEY (c1)
) ENGINE=InnoDB;

実行中のトランザクションが 2 つ存在しており、それぞれ AUTO_INCREMENT カラムを含むテーブル内に行を挿入しているものとします。1 つのトランザクションは 1000 行を挿入する INSERT ... SELECT ステートメントを使用しており、もう 1 つのトランザクションは 1 行を挿入する単純な INSERT ステートメントを使用しています。

Tx1: INSERT INTO t1 (c2) SELECT 1000 rows from another table ...
Tx2: INSERT INTO t1 (c2) VALUES ('xxx');

InnoDB は、Tx1 の INSERT ステートメント内の SELECT から取得される行数を事前に知ることができないため、そのステートメントの処理を進める際に、自動インクリメント値を一度に 1 つずつ割り当てます。ステートメントの終了まで保持されるテーブルレベルロックが存在しているため、ある時点で実行可能な INSERT ステートメントはテーブル t1 を参照している 1 つのステートメントだけであり、複数ステートメントによって自動インクリメント番号の生成がインターリーブされることはありません。Tx1 の INSERT ... SELECT ステートメントで生成される自動インクリメント値は連続した番号となり、Tx2 の INSERT ステートメントで使用される (単一の) 自動インクリメント値は、どちらのステートメントが先に実行されるかに応じて、Tx1 で使用されるすべての値よりも小さいか大きい値になります。

(ステートメントベースのレプリケーション使用時やリカバリシナリオで) バイナリログから再現する際に SQL ステートメントが同じ順番で実行されるかぎり、その結果は、Tx1 と Tx2 が最初に実行されたときと同じになります。したがって、ステートメントの終了まで保持されるテーブルレベルロックが存在することで、自動インクリメントを使用する INSERT ステートメントをステートメントベースのレプリケーションで安全に使用できるようになります。ただし、このようなロックでは、複数のトランザクションで挿入ステートメントが同時に実行されるときの並列性および拡張性が制限されます。

前述の例でテーブルレベルロックが存在しなかった場合、Tx2 の INSERT で使用される自動インクリメントカラムの値は、ステートメントが実際に実行されるタイミングに応じて変更されます。Tx1 の INSERT の (実行前や完了後ではなく) 実行中に、Tx2 の INSERT が実行された場合、その 2 つの INSERT ステートメントで割り当てられる具体的な自動インクリメント値は非決定的となり、実行するたびに値が異なる可能性があります。

InnoDB では、行数が事前にわかっている場合は、INSERT ステートメントのクラスに対してテーブルレベル AUTO-INC ロックが使用されることを回避できますが、ステートメントベースのレプリケーションの決定的な実行および安全性は、引き続き保持されます。さらに、リカバリまたはレプリケーションの一部として SQL ステートメントを再現する際にバイナリログを使用しない場合は、並列性およびパフォーマンスをさらに改善するために、テーブルレベル AUTO-INC ロックの使用を完全に除去できますが、ステートメントで割り当てられた自動インクリメント数のギャップが許可され、並列実行されるステートメントで割り当てられた数がインターリーブされる可能性があるという犠牲が伴います。

ステートメントの処理開始時点で挿入行数がわかっているような INSERT ステートメントでは、InnoDB はロックを一切使用せずに必要な数の自動インクリメント値をすばやく割り当てます。ただし、テーブルレベル AUTO-INC ロックをすでに保持している並列セッションが存在しない場合に限ります (その別のステートメントが処理中に自動インクリメント値を 1 つずつ割り当てるため)。より正確に言えば、このような INSERT ステートメントは、ステートメントの完了までではなく、割り当て処理の期間だけ保持される相互排他ロック (軽量ロック) の制御下で自動インクリメント値を取得します。

この新しいロックスキームを使用すると、拡張性を大幅に改善できますが、元のメカニズムと比べて、自動インクリメント値が割り当てられる方法にわずかな相違が散見されます。InnoDB での自動インクリメントの動作を説明するために、次の説明でいくつかの用語を定義し、サーバーの起動時に設定できる innodb_autoinc_lock_mode 構成パラメータのさまざまな設定を使用した InnoDB の動作について説明します。自動インクリメントロックの動作説明のあとで、追加の注意事項について説明します。

まず、いくつかの定義を次に示します。

  • INSERT のようなステートメント

    INSERTINSERT ... SELECTREPLACEREPLACE ... SELECTLOAD DATA など、テーブル内に新しい行を生成するすべてのステートメントです。

  • 単純挿入

    挿入行数を事前に (ステートメントの初期処理時に) 決定できるステートメントです。これには、ネストしたサブクエリーを持たない単一行および複数行の INSERT および REPLACE ステートメントが含まれますが、INSERT ... ON DUPLICATE KEY UPDATE は含まれません。

  • 一括挿入

    挿入行数 (および必要な自動インクリメント値の数) が事前にわからないステートメントです。これには、INSERT ... SELECTREPLACE ... SELECT、および LOAD DATA ステートメントが含まれますが、単純な INSERT は含まれません。InnoDB は各行を処理する際に、AUTO_INCREMENT カラムの新しい値を一度に 1 つずつ割り当てます。

  • 混在モード挿入

    これらは、新しい行の一部 (全部ではない) の自動インクリメント値を指定する 単純挿入 ステートメントです。次の例を示します。c1 はテーブル t1AUTO_INCREMENT カラムです。

    INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

    INSERT ... ON DUPLICATE KEY UPDATE は別のタイプの 混在モード挿入 で、最悪の場合には実質 INSERT のあとに UPDATE を実行することに相当しますが、AUTO_INCREMENT カラムに割り当てられた値は、更新フェーズで使用される可能性も使用されない可能性もあります。

innodb_autoinc_lock_mode パラメータには、次の 3 つの設定を指定できます。

  • innodb_autoinc_lock_mode = 0 (従来 ロックモード)

    このロックモードでは、innodb_autoinc_lock_mode が存在する前と同じ動作が提供されます。すべての INSERT のようなステートメントでは、特殊なテーブルレベル AUTO-INC ロックが取得され、ステートメントの終了まで保持されます。これにより、特定のステートメントによって割り当てられた自動インクリメント値が連続的になります。

    このロックモードの用途は次のとおりです。

    • 下位互換性。

    • パフォーマンスのテスト。

    • 混在モード挿入での問題の対処 (あとで説明するセマンティクスに相違がある可能性があるため)。

  • innodb_autoinc_lock_mode = 1 (連続 ロックモード)

    これがデフォルトのロックモードです。このモードでは、一括挿入 は特殊な AUTO-INC テーブルレベルロックを使用し、そのロックをステートメントの終了まで保持します。これは、INSERT ... SELECTREPLACE ... SELECTLOAD DATA のすべてのステートメントに当てはまります。一度に実行できるステートメントは、AUTO-INC ロックを保持している 1 つのステートメントだけです。

    このロックモードでは、単純挿入 (のみ) が、自動インクリメント値の割り当てのときに軽量相互排他ロックが使用される新しいロックモデルを使用します。別のトランザクションがテーブルレベル AUTO-INC ロックを保持していないかぎり、AUTO-INC ロックは使用されません。別のトランザクションが AUTO-INC ロックを保持している場合、単純挿入一括ロックと同様に、AUTO-INC ロックを待機します。

    このロックモードでは、行数が事前にわからない (したがってステートメントの処理中に自動インクリメント番号が割り当てられる) INSERT ステートメントが存在する場合には、任意の INSERT のような ステートメントによって割り当てられたすべての自動インクリメント値が必ず連続した値になるため、その処理は、ステートメントベースのレプリケーションで使用しても安全です。

    簡単に言えば、このロックモードの重要な効果は、拡張性の大幅な向上です。このモードは、ステートメントベースのレプリケーションで使用しても安全です。さらに、従来ロックモードの場合と同じく、任意のステートメントによって割り当てられた自動インクリメント番号が連続的になります。このモードでは 従来 モードと比較して、1 つの重要な例外を除けば、自動インクリメントを使用するステートメントのセマンティクスに変更点はありません

    例外は混在モード挿入です。この挿入では、ユーザーは複数行の単純挿入で、明示的な値を全部ではなく、一部の行の AUTO_INCREMENT カラムに指定します。このような挿入の場合、InnoDB は挿入される行数よりも大きい自動インクリメント値を割り当てます。ただし、自動的に割り当てられる値はすべて連続的に生成されるため、直前に実行されたステートメントによって生成された自動インクリメント値よりも値が大きくなります。余分な番号は失われます。

  • innodb_autoinc_lock_mode = 2 (インターリーブ ロックモード)

    このロックモードでは、テーブルレベル AUTO-INC ロックを使用する INSERT のようなステートメントは 1 つも存在しないため、複数のステートメントを同時に実行できます。これはもっとも高速で、もっとも拡張性の高いロックモードです。ただし、ステートメントベースのレプリケーションを使用する場合や、リカバリシナリオでバイナリログから SQL ステートメントを再現する際には、安全ではありません

    このロックモードでは、自動インクリメント値は一意であり、並列実行されているすべての INSERT のようなステートメントにわたって単調に増加することが保証されます。ただし、複数のステートメントが同時に番号を生成している (つまり番号の割り当てが複数のステートメント間でインターリーブされている) 可能性があるため、任意のステートメントによって挿入される行に対して生成された値が連続的でない可能性があります。

    唯一のステートメントの実行が、挿入される行数が事前にわかっている単純挿入である場合は、混在モード挿入を除いて、単一のステートメントで生成される数にギャップがありません。ただし、一括挿入が実行されると、特定のステートメントで割り当てられた自動インクリメント値にギャップが発生する可能性があります。

innodb_autoinc_lock_mode によって提供される自動インクリメントロックモードには、次のように使用上の暗黙の前提がいくつかあります。

  • レプリケーションでの自動インクリメントの使用

    ステートメントベースレプリケーションを使用している場合は、innodb_autoinc_lock_mode を 0 または 1 に設定し、マスターとそのスレーブで同じ値を使用してください。innodb_autoinc_lock_mode = 2 (インターリーブ)、またはマスターとスレーブが同じロックモードを使用しない構成を使用する場合は、マスターとスレーブで自動インクリメント値が同じになることは保証されません。

    行ベースレプリケーションは SQL ステートメントの実行順序に左右されない (混在形式は、ステートメントベースレプリケーションでは安全でないステートメントで行ベースレプリケーションを使用する) ため、行ベースまたは混在形式レプリケーションを使用している場合は、すべての自動インクリメントロックモードが安全です。

  • 失われた自動インクリメント値とシーケンスギャップ

    すべてのロックモード (0、1、および 2) では、自動インクリメント値を生成したトランザクションがロールバックされると、これらの自動インクリメント値が失われますINSERT のようなステートメントが完了したかどうか、およびそれを含むトランザクションがロールバックされたかどうかに関係なく、自動インクリメントカラムの値は一度生成されたら、ロールバックできません。このような失われた値は再使用されません。したがって、テーブルの AUTO_INCREMENT カラムに格納されている値にはギャップが存在する可能性があります。

  • 一括挿入の自動インクリメント値のギャップ

    innodb_autoinc_lock_mode が 0 (従来) または 1 (連続) に設定されている場合、テーブルレベル AUTO-INC ロックがステートメントの終了まで保持され、同時に実行できるステートメントはこのような 1 つのステートメントだけであるため、任意のステートメントによって生成される自動インクリメント値は、ギャップのない連続的なものとなります。

    innodb_autoinc_lock_mode が 2 (インターリーブ) に設定されている場合、一括挿入によって生成された自動インクリメント値にギャップが存在する可能性がありますが、並列実行中の INSERT のようなステートメントが存在する場合に限ります。

    一括挿入では、各ステートメントで必要となる自動インクリメント値の正確な数がわからず、過大評価される可能性があるため、ロックモードが 1 または 2 の場合は、連続したステートメント間でギャップが発生する可能性があります。

  • 混在モード挿入によって割り当てられる自動インクリメント値

    単純挿入が (全部ではなく) 一部の結果行の自動インクリメント値を指定する混在モード挿入を検討します。このようなステートメントの動作は、ロックモード 0、1、および 2 で異なります。たとえば、c1 はテーブル t1AUTO_INCREMENT カラムで、自動生成されたシーケンス番号の最新値が 100 であるとします。次のような混在モード挿入ステートメントを検討します。

    INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

    innodb_autoinc_lock_mode が 0 (従来) に設定されている場合、4 つの新しい行は次のようになります。

    +-----+------+
    | c1 | c2 |
    +-----+------+
    | 1 | a |
    | 101 | b |
    | 5 | c |
    | 102 | d |
    +-----+------+

    自動インクリメント値は、ステートメントの実行開始時に一度にすべての値が割り当てられるのではなく、一度に 1 つずつ割り当てられるため、次に使用可能な自動インクリメント値は 103 になります。この結果は、並列実行中の (任意の型の) INSERT のようなステートメントが存在するかどうかに左右されません。

    innodb_autoinc_lock_mode が 1 (連続) に設定されている場合も、4 つの新しい行は次のようになります。

    +-----+------+
    | c1 | c2 |
    +-----+------+
    | 1 | a |
    | 101 | b |
    | 5 | c |
    | 102 | d |
    +-----+------+

    ただし、この場合、ステートメントの処理時に自動インクリメント値が 4 つ割り当てられましたが、そのうちの 2 つだけが使用されたため、次に使用可能な自動インクリメント値は 103 ではなく、105 になります。この結果は、並列実行中の (任意の型の) INSERT のようなステートメントが存在するかどうかに左右されません。

    innodb_autoinc_lock_mode が 2 (インターリーブ) に設定されている場合、4 つの新しい行は次のようになります。

    +-----+------+
    | c1 | c2 |
    +-----+------+
    | 1 | a |
    | x | b |
    | 5 | c |
    | y | d |
    +-----+------+

    xy の値は一意であり、以前に生成されたどの行よりも大きくなります。ただし、xy の具体的な値は、並列実行中のステートメントによって生成された自動インクリメント値の個数によって変わります。

    最後に、生成された最新のシーケンス番号が値 4 だったときに、次のステートメントを発行した場合を検討します。

    INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');

    どのように innodb_autoinc_lock_mode を設定しても、行 (NULL, 'b') に対して 5 が割り当てられ、行 (5, 'c') の挿入が失敗するため、このステートメントから重複キーエラー 23000 (Can't write; duplicate key in table) が生成されます。

14.6.6 InnoDB と FOREIGN KEY 制約

このセクションでは、InnoDB ストレージエンジンでの外部キー処理と、MySQL サーバーでの処理とを比較したときの相違点について説明します。

外部キーの定義

InnoDB テーブルの外部キー定義は、次のような条件の対象となります。

  • InnoDB では、外部キーが任意のインデックスカラムまたはカラムのグループを参照することが許可されます。ただし、参照されるテーブルには、参照されるカラムが同じ順序で最初のカラムとして一覧表示されているインデックスが存在する必要があります。

  • 現在、InnoDB ではユーザー定義のパーティションを持つテーブルの外部キーがサポートされていません。つまり、ユーザーがパーティション化した InnoDB テーブルには、外部キーで参照される外部キー参照またはカラムが含まれる可能性がありません。

  • InnoDB では、外部キー制約が一意でないキーを参照することが許可されます。これは、標準 SQL の InnoDB 拡張です。

参照アクション

InnoDB テーブルの外部キーに関する参照アクションは、次のような条件の対象となります。

  • SET DEFAULT は、MySQL サーバーで許可されていますが、InnoDB では無効として拒否されます。この句を使用した CREATE TABLE および ALTER TABLE ステートメントは、InnoDB テーブルで許可されていません。

  • 同じ参照キー値を持つ複数の行が親テーブルにある場合、InnoDB は、同じキー値を持つほかの親の行が存在しないかのように、外部キーチェックで動作します。たとえば、RESTRICT 型の制約が定義されていて、複数の親の行を含む子の行が存在する場合は、これらの親の行のいずれかを削除することが InnoDB で許可されません。

  • InnoDB では、外部キー制約に対応するインデックス内のレコードに基づいて、深さ優先アルゴリズムを使用したカスケード操作が実行されます。

  • ON UPDATE CASCADE または ON UPDATE SET NULL は、カスケード中に以前に更新していた同じテーブルを更新するように再帰する場合、RESTRICT と同様に機能します。つまり、自己参照型 ON UPDATE CASCADE または ON UPDATE SET NULL 操作は使用できません。この目的は、カスケード更新で発生する無限ループを回避することです。反対に、自己参照型 ON DELETE SET NULL は、自己参照型 ON DELETE CASCADE と同様に動作できます。カスケード操作は、15 レベルよりも深くネストされる可能性がありません。

  • 一般的な MySQL と同様に、多数の行を挿入、削除、または更新する SQL ステートメントでは、InnoDB によって UNIQUE および FOREIGN KEY 制約が 1 行ずつチェックされます。外部キーチェックの実行時に、InnoDB は、調査対象の子または親のレコード上に共有の行レベルロックを設定します。InnoDB では、即座に外部キー制約がチェックされ、そのチェックはトランザクションのコミットまで遅延されません。SQL 標準によると、デフォルトの動作は遅延チェックにするべきです。つまり、SQL ステートメント全体が処理されたあとにはじめて、制約がチェックされます。InnoDB で制約の遅延チェックが実装されるまで、外部キーを使用してそれ自体を参照するレコードを削除するなどの一部の操作が実行できません。

外部キーの使用法とエラー情報

外部キーおよびそれらの使用法に関する一般的な情報は、INFORMATION_SCHEMA.KEY_COLUMN_USAGE テーブルでクエリーを実行することで取得できます。InnoDB テーブルに固有の詳細な情報は、INNODB_SYS_FOREIGN および INNODB_SYS_FOREIGN_COLS テーブル、または INFORMATION_SCHEMA データベースで見つかります。セクション13.1.17.2「外部キー制約の使用」も参照してください。

SHOW ERRORS 以外でも、InnoDB テーブルが関与する外部キーエラー (通常、MySQL サーバーではエラー 150) の発生時に、SHOW ENGINE INNODB STATUS の出力をチェックすることで、最近の InnoDB 外部キーエラーの詳細な説明を取得できます。

14.6.7 InnoDB テーブル上の制限

警告

mysql データベース内の MySQL システムテーブルを MyISAM から InnoDB テーブルに変換しないでください。これはサポートされていない操作です。これを行うと、mysql_install_db プログラムを使用してバックアップから古いシステムテーブルをリストアするか、再生成するまで、MySQL は再起動されません。

警告

NFS ボリューム上でデータファイルやログファイルが使用されるように InnoDB を構成することは、適切ではありません。それ以外の場合は、ファイルがほかのプロセスによってロックされ、MySQL で使用できなくなる可能性があります。

最大と最小

  • テーブルには、最大で 1017 個のカラムを含めることができます (MySQL 5.6.9 で、以前の 1000 個の制限から上昇されました)。

  • テーブルには、最大で 64 個のセカンダリインデックスを含めることができます。

  • デフォルトでは、単一カラムインデックスのインデックスキーを最大で 767 バイトにすることができます。インデックスキープリフィクスにも同じ長さ制限が適用されます。セクション13.1.13「CREATE INDEX 構文」を参照してください。たとえば、UTF-8 文字セットと文字ごとに最大 3 バイトを使用すると仮定すれば、TEXT または VARCHAR カラム上で 255 文字よりも長いカラムプリフィクスインデックスを使用すると、この制限に達する可能性があります。innodb_large_prefix 構成オプションを有効にすると、DYNAMIC および COMPRESSED 行フォーマットを使用する InnoDB テーブルで、この長さ制限が 3072 バイトに上昇します。

    許可されている最大値よりも長いインデックスプリフィクス長を使用しようとすると、エラーが生成されます。スレーブ上でも innodb_large_prefix オプションを設定できなく、この制限の影響を受ける可能性のある一意のインデックスをスレーブが持っている場合は、レプリケーション構成でこのようなエラーを回避するために、このオプションをマスター上で設定することを避けてください。

  • InnoDB の内部的な最大キー長は 3500 バイトですが、MySQL 自体では 3072 バイトに制限されています。この制限は、複数カラムインデックス内の結合されたインデックスキーの長さに適用されます。

  • MySQL インスタンスの作成時に innodb_page_size オプションを指定して、InnoDBページサイズを 8K バイトまたは 4K バイトまで小さくすると、16K バイトのページサイズに対応する 3072 バイトの制限に基づいて、比例的にインデックスキーの最大長も短くなります。つまり、インデックスキーの最大長は、ページサイズが 8K バイトのときは 1536 バイト、ページサイズが 4K バイトのときは 768 バイトになります。

  • 可変長カラム (VARBINARYVARCHARBLOB、および TEXT) を除き、行の最大長はデータベースページの半分より少し短くなります。つまり、デフォルトページサイズの 16K バイトでは、行の最大長が約 8000 バイトになります。MySQL インスタンスの作成時に innodb_page_size オプションを指定してページサイズを小さくすると、行の最大長は、8K バイトのページでは 4000 バイト、4K バイトのページでは 2000 バイトになります。LONGBLOB および LONGTEXT カラムは 4G バイト未満である必要があり、BLOB および TEXT カラムを含む行全体の長さは 4G バイト未満である必要があります。

    行の長さが 1 ページの半分より短い場合は、行全体がそのページ内にローカルに格納されます。セクション14.10.2「ファイル領域管理」で説明したように、半ページを超える行では、その行が半ページ以内に収まるように、可変長カラムが外部オフページストレージの対象として選択されます。

  • InnoDB では内部的に 65,535 バイトを超える行サイズがサポートされていますが、MySQL 自体では、すべてのカラムを結合したサイズに 65,535 行のサイズ制限が課されています。

    mysql> CREATE TABLE t (a VARCHAR(8000), b VARCHAR(10000), -> c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000), -> f VARCHAR(10000), g VARCHAR(10000)) ENGINE=InnoDB;ERROR 1118 (42000): Row size too large. The maximum row size for the
    used table type, not counting BLOBs, is 65535. You have to change some
    columns to TEXT or BLOBs

    セクションD.10.4「テーブルカラム数と行サイズの制限」を参照してください。

  • 一部の古いオペレーティングシステムでは、ファイルは 2G バイトよりも小さくする必要があります。これは、InnoDB 自体の制限ではありません。ただし、大きいテーブルスペースが必要な場合は、1 つではなく複数の小さいデータファイルを使用して構成するか、より大きいデータファイルを作成する必要があります。

  • InnoDB ログファイルを結合したサイズは、最大で 512G バイトまでにすることができます。

  • テーブルスペースの最小サイズは、10M バイトをわずかに超える大きさです。テーブルスペースの最大サイズは、40 億データベースページ (64T バイト) です。これはテーブルの最大サイズでもあります。

  • InnoDB のデフォルトのデータベースページサイズは 16K バイトですが、MySQL インスタンスの作成時に innodb_page_size オプションを指定すれば、ページサイズを 8K バイトまたは 4K バイトまで小さくすることができます。

    注記

    ページサイズを大きくすることは、サポートされている操作ではありません。InnoDB では、16K バイトを超えるページサイズでは通常な動作が保証されません。InnoDB をコンパイルまたは実行するときに、問題が発生する可能性があります。特に、Barracuda ファイル形式の ROW_FORMAT=COMPRESSED では、ページサイズが 16K バイトで、14 ビットのポインタを使用することが前提となっています。

    特定の InnoDB ページサイズを使用している MySQL インスタンスは、別のページサイズを使用するインスタンスのデータファイルやログファイルを使用できません。この制限によって、16K バイト以外のページサイズがサポートされている MySQL 5.6 のデータを使用したリストアまたはダウングレード操作が影響を受ける可能性があります。

インデックスの型

  • MySQL 5.6.4 以降では、InnoDB テーブルで FULLTEXT インデックスがサポートされています。詳細は、セクション14.2.13.3「FULLTEXT インデックス」を参照してください。

  • InnoDB テーブルでは空間データ型がサポートされますが、そのインデックスはサポートされません。

InnoDB テーブル上の制約

  • 各インデックスツリーにランダムダイブを行い、それに従ってインデックスカーディナリティーの見積もりを更新すると、(SHOW INDEX 出力の「Cardinality」カラムに表示されるように) ANALYZE TABLE でインデックスカーディナリティーが決定されます。これらは単なる見積もりであるため、ANALYZE TABLE を繰り返し実行すると、別の数値が生成される可能性があります。これによって ANALYZE TABLEInnoDB テーブル上での速度は速くなりますが、すべての行が考慮されているわけではないため、100% 正確とは言えません。

    セクション14.13.16.1「永続的オプティマイザ統計のパラメータの構成」で説明したように、innodb_stats_persistent 構成オプションをオンにすると、ANALYZE TABLE で収集された統計の正確性および安定性を向上させることができます。統計は定期的に再計算されないため、この設定を有効にした場合は、従来と同様に、インデックス付きカラムデータの主要な変更後 (サーバーの再起動後など) に、ANALYZE TABLE を実行することが重要です。

    innodb_stats_persistent_sample_pages システム変数 (永続的な統計設定がオンになっている場合)、または innodb_stats_transient_sample_pages システム変数 (永続的な統計設定がオフになっている場合) を変更すると、ランダムダイブの数を変更できます。

    MySQL では、結合の最適化時にのみインデックスカーディナリティーの見積もりが使用されます。一部の結合が適切に最適化されない場合は、ANALYZE TABLE を使用してみてください。ANALYZE TABLE では特定のテーブルに十分な値が生成されない場合は、特定のインデックスの使用を強制するクエリーとともに FORCE INDEX を使用するか、または MySQL でテーブルスキャンよりもインデックス検索が優先されるように max_seeks_for_key システム変数を設定してください。セクション5.1.4「サーバーシステム変数」、およびセクションB.5.6「オプティマイザ関連の問題」を参照してください。

  • テーブル上でステートメントまたはトランザクションが実行されていて、ANALYZE TABLE のあとに同じテーブル上で 2 番目の ANALYZE TABLE 操作が実行されると、そのステートメントまたはトランザクションが完了するまで、2 番目の ANALYZE TABLE 操作はブロックされます。この動作が発生する原因は、ANALYZE TABLE の実行が完了すると、ANALYZE TABLE によって現在ロード中のテーブル定義に非推奨のマークが付けられるためです。新しいステートメントまたはトランザクション (2 番目の ANALYZE TABLE ステートメントを含む) は、新しいテーブル定義をテーブルキャッシュにロードする必要があります。この動作は、現在実行中のステートメントまたはトランザクションが完了し、古いテーブル定義がパージされるまで発生する可能性がありません。複数の並列テーブル定義をロードすることは、サポートされていません。

  • SHOW TABLE STATUS では、テーブルで予約された物理サイズを除き、InnoDB テーブルに関する正確な統計が得られません。行カウントは、単に SQL 最適化で使用される概算見積もりです。

  • 並列トランザクションでは同時にさまざまな数の行が参照される可能性があるため、InnoDB のテーブルには、行の内部的なカウントが保持されません。SELECT COUNT(*) FROM t ステートメントを処理するために、InnoDB ではテーブルのインデックスがスキャンされますが、インデックスが完全にバッファープール内にない場合は多少時間がかかります。テーブルが頻繁に変更されない場合は、MySQL クエリーキャッシュを使用することが適切な解決策となります。すばやくカウントするには、自分で作成したカウンタテーブルを使用し、実行される挿入および削除に応じてアプリケーションで更新できるようにする必要があります。概算の行カウントでは十分でない場合は、SHOW TABLE STATUS を使用できます。セクション8.5「InnoDB テーブルの最適化」を参照してください。

  • Windows 上の InnoDB では常に、データベース名およびテーブル名が内部的に小文字で格納されます。バイナリ形式のデータベースを Unix から Windows に、または Windows から Unix に移動するには、すべてのデータベースおよびテーブルを小文字の名前を使用して作成します。

  • 最大カラム値を取得するためにテーブルでのインデックス付きの SELECT MAX(ai_col) 検索と同等の操作を実行できるように、AUTO_INCREMENT カラム ai_col をインデックスの一部として定義する必要があります。一般に、これはカラムをどこかのテーブルインデックスの 1 番目のカラムにすることで実現されます。

  • InnoDB は、テーブル上に事前に指定された AUTO_INCREMENT カラムの初期化中に、AUTO_INCREMENT カラムに関連付けられたインデックスの最後に排他ロックを設定します。自動インクリメントカウンタにアクセスするときに InnoDB では、トランザクション全体の最後までではなく、現在の SQL ステートメントの最後まで存続する特別な AUTO-INC テーブルロックモードが使用されます。AUTO-INC テーブルロックが保持されている間は、ほかのクライアントはそのテーブルに挿入できません。セクション14.6.5「InnoDB での AUTO_INCREMENT 処理」を参照してください。

  • MySQL サーバーを再起動すると、AUTO_INCREMENT カラム用に生成されたが一度も格納されなかった古い値 (つまり、ロールバックされた古いトランザクション内で生成された値) が InnoDB で再使用される可能性があります。

  • AUTO_INCREMENT 整数カラムの値を使い果たすと、後続の INSERT 操作で重複キーエラーが返されます。これは一般的な MySQL の動作であり、MyISAM の動作と似ています。

  • DELETE FROM tbl_name はテーブルを再生成しませんが、その代わりにすべての行を 1 つずつ削除します。

  • 現在、カスケードされた外部キーのアクションではトリガーがアクティブになっていません。

  • 内部 InnoDB カラム (DB_ROW_IDDB_TRX_IDDB_ROLL_PTRDB_MIX_ID など) の名前と一致するカラム名を持つテーブルを作成することはできません。サーバーはエラー 1005 をレポートし、エラーメッセージ内のエラー −1 を参照します。この制約は、大文字の名前を使用する場合にのみ適用されます。

ロックとトランザクション

  • innodb_table_locks=1 (デフォルト) の場合、LOCK TABLES で各テーブル上に 2 つのロックが取得されます。MySQL レイヤーでのテーブルロックに加えて、InnoDB テーブルロックも取得されます。バージョン 4.1.2 よりも前の MySQL では、InnoDB テーブルロックが取得されませんでした。この古い動作は、innodb_table_locks=0 を設定すれば選択できます。InnoDB テーブルロックが取得されない場合は、テーブルの一部のレコードがほかのトランザクションによってロックされなくても、LOCK TABLES が完了します。

    MySQL 5.6 では、LOCK TABLES ... WRITE を使用して明示的にロックされたテーブルには、innodb_table_locks=0 が無効です。LOCK TABLES ... WRITE で暗黙的に (たとえば、トリガーを使用して)、または LOCK TABLES ... READ によって、読み取りまたは書き込み用にロックされたテーブルには有効です。

  • トランザクションで保持されているすべての InnoDB ロックは、トランザクションがコミットまたは中止されると解放されます。したがって、autocommit=1 モードの InnoDB テーブル上で LOCK TABLES を呼び出しても、取得された InnoDB テーブルロックはすぐに解放されてしまうため、まったく意味がありません。

  • LOCK TABLES では暗黙的な COMMIT および UNLOCK TABLES が実行されるため、トランザクションの実行中に追加のテーブルをロックできません。

  • 並列データ変更トランザクションの 1023 個の制限は、MySQL 5.5 以上で上昇されました。現在、その制限は、Undo レコードが生成される 128 * 1023 個の並列トランザクションになりました。適切なトランザクション構造を変更する必要のある回避策 (より頻繁にコミットするなど) をすべて解除できます。

14.7 InnoDB 圧縮テーブル

圧縮するための SQL 構文および MySQL 構成オプションを使用すると、データが圧縮形式で格納されるテーブルを作成できます。圧縮を使用すると、生のパフォーマンスと拡張性の両方を改善する際に役立つことがあります。圧縮とは、ディスクとメモリー間で転送されるデータの量が少なくなり、ディスク上とメモリー内で占有される領域の量が少なくなることを意味します。インデックスデータも圧縮されるため、セカンダリインデックスを含むテーブルでは利点も増幅されます。SSD ストレージデバイスは、HDD デバイスよりも容量が小さくなる傾向があるため、圧縮が特に重要となる可能性があります。

14.7.1 テーブル圧縮の概要

プロセッサおよびキャッシュメモリーは、ディスクストレージデバイスよりも速度が上昇しているため、多くのワークロードがディスクバウンドになります。データ圧縮を使用すると、データベースのサイズが小さくなり、I/O が削減され、スループットが改善されますが、CPU 使用率が上昇するという少しの犠牲が伴います。圧縮は、頻繁に使用されるデータをメモリー内に保持するために十分な RAM が搭載されたシステム上で、読み取り負荷の高いアプリケーションを実行する際に、特に有効です。

ROW_FORMAT=COMPRESSED で作成された InnoDB テーブルでは、通常の 16K バイトのデフォルトよりも小さいページサイズをディスク上で使用できます。ページが小さいほど、ディスクから読み取られる I/O とディスクに書き込まれる I/O が少なくなるため、SSD デバイスを使用する際に、特に有効です。

ページサイズは、KEY_BLOCK_SIZE パラメータを使用して指定されます。ページサイズが異なる場合は、テーブルをシステムテーブルスペース内でなく、独自の .ibd ファイルに格納する必要があります。そのためには、innodb_file_per_table オプションを有効にする必要があります。圧縮レベルは、KEY_BLOCK_SIZE の値に関係なく同じです。KEY_BLOCK_SIZE に小さい値を指定するほど、徐々にページが小さくなるという I/O の利点が得られます。ただし、小さすぎる値を指定すると、各ページ内に複数の行を収容できるほど十分にデータ値を圧縮できない場合に、ページを再編成するための追加のオーバーヘッドが発生します。そのインデックスごとのキーカラムの長さに基づいて、どのくらい小さい KEY_BLOCK_SIZE をテーブルに指定できるのかについて、ハード制限が課されています。小さすぎる値を指定すると、CREATE TABLE または ALTER TABLE ステートメントが失敗します。

バッファープールには、圧縮済みデータが KEY_BLOCK_SIZE の値に基づいたページサイズの小さなページで保持されます。カラム値を抽出または更新すると、MySQL のバッファープールには、非圧縮データを含む 16K バイトのページも作成されます。バッファープール内では、非圧縮ページへの更新が同等の圧縮済みページに再度書き込まれます。圧縮済みページと非圧縮ページの両方の追加データが収容されるように、バッファーページのサイズを変更する必要がある場合もあります。ただし、非圧縮のページは、領域が必要になるとバッファープールから解放され、次のアクセス時に再度圧縮が解除されます。

14.7.2 テーブル圧縮の有効化

圧縮テーブルを作成する前に、innodb_file_per_table 構成オプションが有効になっていること、および innodb_file_formatBarracuda に設定されていることを確認してください。これらのパラメータは、MySQL 構成ファイルmy.cnf または my.ini で設定することも、MySQL サーバーをシャットダウンせずに SET ステートメントを使用して設定することもできます。

テーブルの圧縮を有効にするには、CREATE TABLE または ALTER TABLE ステートメントで ROW_FORMAT=COMPRESSED 句、KEY_BLOCK_SIZE 句、またはその両方を使用します。

圧縮テーブルを作成するには、次のようなステートメントを使用するとよいでしょう。

SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_file_format=Barracuda;
CREATE TABLE t1 (c1 INT PRIMARY KEY) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
  • ROW_FORMAT=COMPRESSED を指定する場合は、KEY_BLOCK_SIZE を省略できます。innodb_page_size 値の半分であるデフォルトのページサイズ値が使用されます。

  • KEY_BLOCK_SIZE を指定する場合は、ROW_FORMAT=COMPRESSED を省略できます。圧縮は自動的に有効になります。

  • KEY_BLOCK_SIZE の最適な値を決定するには、一般に、この句にさまざまな値を指定した同じテーブルのコピーをいくつか作成してから、結果として生成される .ibd ファイルのサイズを計測し、現実的なワークロードで各動作のパフォーマンスを確認します。

  • KEY_BLOCK_SIZE 値は、ヒントとして処理されます。InnoDB では、必要に応じて異なるサイズが使用される可能性があります。値 0 は、innodb_page_size 値の半分であるデフォルトの圧縮済みページサイズを表します。KEY_BLOCK_SIZE は、innodb_page_size 値以下にしかできません。innodb_page_size 値を超える値を指定した場合は、指定された値が無視され、警告が発行されます。また、KEY_BLOCK_SIZEinnodb_page_size 値の半分に設定されます。innodb_strict_mode=ON の場合、無効な KEY_BLOCK_SIZE 値を指定するとエラーが返されます。

  • パフォーマンス関連の追加の構成オプションについては、セクション14.7.3「InnoDB テーブルの圧縮の調整」を参照してください。

InnoDB データページのデフォルトの非圧縮サイズは、16K バイトです。オプション値の組み合わせに応じて、MySQL ではテーブルの .ibd ファイルに対応した 1K バイト、2K バイト、4K バイト、8K バイト、または 16K バイトのページサイズが使用されます。実際の圧縮アルゴリズムは、KEY_BLOCK_SIZE 値の影響を受けません。この値によって、各圧縮済みチャンクの大きさが決定されるため、各圧縮済みページに詰め込むことができる行数が影響を受けます。

一般に、KEY_BLOCK_SIZEInnoDBページサイズに等しい値に設定しても、大量の圧縮は発生しません。たとえば、InnoDBページサイズは 16K バイトであるため、一般に KEY_BLOCK_SIZE=16 を設定しても、大量の圧縮は発生しません。多くの場合、このような値で適切に圧縮されるため、この設定は多くの長い BLOBVARCHAR、または TEXT カラムを持つテーブルで引き続き役立つことがあります。したがって、セクション14.7.5「InnoDB テーブルでの圧縮の動作」で説明したように、必要となるオーバーフローページが少なくなる可能性もあります。

テーブルのすべてのインデックス (クラスタ化されたインデックスを含む) は、CREATE TABLE または ALTER TABLE ステートメントで指定されたものと同じページサイズを使用して圧縮されます。ROW_FORMATKEY_BLOCK_SIZE などのテーブル属性は、InnoDB テーブルの CREATE INDEX 構文の一部ではないため、指定しても無視されます (ただし、SHOW CREATE TABLE ステートメントの出力には表示されます)。

圧縮テーブル上の制約

バージョン 5.1 よりも前の MySQL では圧縮テーブルを処理できないため、圧縮を使用するには、偶然に互換性の問題が発生することを回避するために、innodb_file_format=Barracuda 構成パラメータを指定する必要があります。

テーブルの圧縮は、InnoDB のシステムテーブルスペースでも使用できません。システムテーブルスペース (スペース 0、ibdata* ファイル) にはユーザーデータを含めることができますが、内部システム情報も含まれているため、圧縮されません。そのため、圧縮は独自のテーブルスペースに格納されているテーブル (およびインデックス) にのみ適用されます。つまり、innodb_file_per_table オプションが有効になっている状態で作成されます。

句の名前が ROW_FORMAT であるにもかかわらず、圧縮は個別の行にではなく、テーブル全体およびそれに関連付けられたすべてのインデックスに適用されます。

14.7.3 InnoDB テーブルの圧縮の調整

ほとんどの場合、InnoDB Data Storage and Compressionで説明した内部的な最適化によって、圧縮済みデータを使用してもシステムは適切に動作します。ただし、圧縮の効率性はデータの特性によって異なるため、圧縮テーブルのパフォーマンスに影響を与える決定を行うことができます。

  • 圧縮するテーブル。

  • 使用する圧縮済みページサイズ。

  • 実行時のパフォーマンス特性 (システムでデータの圧縮および圧縮解除に要する時間など) に基づいて、バッファープールのサイズを調整するかどうか。ワークロードがデータウェアハウス (主にクエリー) または OLTP システム (クエリーと DML の混在) に似ているかどうか。

  • システムの圧縮テーブル上で DML 操作が実行されているときに、データを配布する方法によって実行時に負荷の高い圧縮が失敗する場合は、追加の高度な構成オプションを調整することがあります。

このセクションのガイドラインを使用すると、このようなアーキテクチャー上および構成上の選択を行う際に役立ちます。長期間のテストを実施し、圧縮テーブルを本番環境に移行する準備ができたら、これらの選択を現実の状況で行なった場合の効率性を検証する方法について、セクション14.7.4「実行時の圧縮のモニタリング」を参照してください。

圧縮を使用するタイミング

一般に、圧縮は、適当な数の文字列カラムが含まれ、データの書き込みよりも読み取りの頻度の方がはるかに高いテーブルで最適に動作します。特定の状況で圧縮の利点が得られるかどうかを予測するための保証された方法はないため、必ず、代表的な構成で実行する特定のワークロードおよびデータセットをテストしてください。圧縮するテーブルを決定する際は、次の要素を検討してください。

データの特性と圧縮

データファイルのサイズを削減する際に圧縮の効率性の決定要因となるものは、データ自体の特性です。圧縮は、データのブロックで繰り返されるバイト文字列を識別することで動作していることを思い出してください。完全にランダム化されたデータは、最悪のケースです。多くの場合、一般的なデータには繰り返し値が含まれているため、効率的に圧縮されます。CHARVARCHARTEXT、または BLOB のいずれのカラムに定義されているのかに関係なく、多くの場合、文字列は効率的に圧縮されます。その一方で、一般に、ほとんどがバイナリデータ (整数または浮動小数) や以前に圧縮されたデータ (JPEG または PNG イメージなど) を含むテーブルは、大幅にまたはまったく効率的に圧縮されない可能性があります。

InnoDB テーブルごとに圧縮を有効にするかどうかを選択します。テーブルおよびそのすべてのインデックスでは、同じ (圧縮済み) ページサイズが使用されます。すべてのテーブルカラムのデータを含む主キー (クラスタ化) インデックスは、セカンダリインデックスよりも効率的に圧縮される可能性があります。長い行が存在する場合に圧縮を使用すると、セクション14.9.3「DYNAMIC および COMPRESSED 行フォーマット」で説明したように、長いカラム値がオフページに格納される可能性があります。このようなオーバーフローページは、効率的に圧縮される可能性があります。これらの検討事項を考慮すると、多くのアプリケーションでは、一部のテーブルがその他よりも効率的に圧縮され、圧縮されたテーブルのサブセットを含むワークロードのみが最適に動作する場合もあります。

特定のテーブルを圧縮するかどうかを決定するには、実験を行います。非圧縮テーブルの .ibd ファイルのコピー上に、LZ77 圧縮 (gzip や WinZip など) が実装されたユーティリティーを使用すると、データを圧縮する際の効率性の概算見積もりを取得できます。MySQL ではページサイズ (デフォルトは 16K バイト) に基づいたチャンク単位でデータが圧縮されるため、MySQL で圧縮されたテーブルからは、ファイルベースの圧縮ツールよりも低い圧縮率が得られると予測できます。ページ形式には、ユーザーデータに加えて、圧縮されていない内部システムデータもいくつか含まれます。ファイルベースの圧縮ユーティリティーでは、さらに大きなデータチャンクを調査できるため、MySQL の各ページで見つかるよりも多くの繰り返し文字列が巨大なファイルで見つかる可能性があります。

特定のテーブル上で圧縮をテストするもう 1 つの方法は、いくつかのデータを非圧縮テーブルから同様の (同じインデックスをすべて含む) 圧縮テーブルにコピーし、結果として生成される .ibd ファイルのサイズを確認することです。例:

use test;
set global innodb_file_per_table=1;
set global innodb_file_format=Barracuda;
set global autocommit=0;
-- Create an uncompressed table with a million or two rows.
create table big_table as select * from information_schema.columns;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
commit;
alter table big_table add id int unsigned not null primary key auto_increment;
show create table big_table\G
select count(id) from big_table;
-- Check how much space is needed for the uncompressed table.
\! ls -l data/test/big_table.ibd
create table key_block_size_4 like big_table;
alter table key_block_size_4 key_block_size=4 row_format=compressed;
insert into key_block_size_4 select * from big_table;
commit;
-- Check how much space is needed for a compressed table
-- with particular compression settings.
\! ls -l data/test/key_block_size_4.ibd

この実験では、次のような数値が生成されました。当然、テーブル構造やデータによって、数値が大幅に異なる可能性があります。

-rw-rw---- 1 cirrus staff 310378496 Jan 9 13:44 data/test/big_table.ibd
-rw-rw---- 1 cirrus staff 83886080 Jan 9 15:10 data/test/key_block_size_4.ibd

特定のワークロードで圧縮が効率的かどうかを確認するには:

  • 単純なテストでは、その他の圧縮テーブルが含まれない MySQL インスタンスを使用して、INFORMATION_SCHEMA.INNODB_CMP テーブルに対してクエリーを実行します。

  • 複数の圧縮テーブルが含まれるワークロードが関与するより詳細なテストでは、INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX テーブルに対してクエリーを実行します。INNODB_CMP_PER_INDEX テーブルの統計を収集すると負荷が高くなるため、そのテーブルのクエリーを実行する前に、innodb_cmp_per_index_enabled 構成オプションを有効にする必要があります。このようなテストは、開発サーバーやクリティカルでないスレーブサーバーに限定されることもあります。

  • テスト中の圧縮テーブルに対して、一般的な SQL ステートメントをいくつか実行します。

  • INFORMATION_SCHEMA.INNODB_CMP または INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX テーブルのクエリーを実行し、COMPRESS_OPSCOMPRESS_OPS_OK を比較することで、圧縮操作全体に対する正常な圧縮操作の比率を調査します。

  • 圧縮操作が正常に完了した比率が高い場合は、そのテーブルが圧縮対象の候補である可能性が高くなります。

  • 圧縮が失敗する比率が高い場合は、セクション14.7.6「OLTP ワークロードの圧縮」で説明したように、innodb_compression_levelinnodb_compression_failure_threshold_pct、および innodb_compression_pad_pct_max オプションを調整すれば、さらに詳細なテストを試すことができます。

データベースの圧縮とアプリケーションの圧縮

アプリケーション内とテーブル内のどちらでデータを圧縮するかどうかを決定します。同じデータで両方のタイプの圧縮を使用しないでください。アプリケーション内でデータを圧縮し、その結果を圧縮テーブルに格納すると、追加の領域が節約される可能性は大幅に低くなり、二重圧縮によって単に CPU サイクルが無駄になるだけです。

データベース内での圧縮

これを有効にすると、MySQL テーブルの圧縮は自動的になり、すべてのカラムおよびインデックス値に適用されます。LIKE などの演算子を含むカラムも引き続きテストでき、インデックス値が圧縮されている場合でも、ソート操作でインデックスを引き続き使用できます。多くの場合、インデックスがデータベースの合計サイズの相当な割合を占めるため、圧縮を使用すると、ストレージ、I/O、またはプロセッサ時間が大幅に節約される可能性があります。圧縮および圧縮解除の操作は、予期される負荷を処理できるようにサイズ変更された強力なシステムとなる可能性が高いデータベースサーバー上で発生します。

アプリケーション内での圧縮

テキストなどのデータをアプリケーション内で圧縮してから、データベースに挿入する場合は、一部のカラムは圧縮されるが、その他は圧縮されないことで効率的に圧縮されないデータで、オーバーヘッドが節約される可能性があります。このアプローチでは、圧縮および圧縮解除用の CPU サイクルがデータベースサーバー上ではなく、クライアントマシン上で使用されるため、多数のクライアントが含まれる分散アプリケーションや、予備の CPU サイクルを備えたクライアントマシンに適している場合があります。

ハイブリッドアプローチ

当然、これらのアプローチは組み合わせることができます。一部のアプリケーションでは、いくつかの圧縮テーブルといくつかの非圧縮テーブルを使用することが適切である場合があります。一部のデータを外部で圧縮して (それを非圧縮テーブルに格納して)、アプリケーション内のその他のテーブル (の一部) を MySQL で圧縮できるようにすることが最適な方法である場合もあります。通常どおり、適切な決定に達するには、事前の設計および現実のテストが重要となります。

ワークロードの特性と圧縮

圧縮するテーブル (およびページサイズ) を選択することに加えて、ワークロードはもう 1 つのパフォーマンスの主要な決定要因でもあります。アプリケーションが更新ではなく、読み取りで占有されている場合は、圧縮済みデータ用に MySQL で保持されるページごとの変更ログ用の空き領域がインデックスページによって使い果たされたあとに、再編成および再圧縮する必要のあるページが少なくなります。更新によって、インデックスなしのカラムまたはそれらが含まれている BLOB や、偶然にオフページに格納される大きな文字列が主に変更される場合は、圧縮のオーバーヘッドが許容可能になる可能性があります。単調に増加する主キーを使用する INSERT がテーブルへの唯一の変更であり、セカンダリインデックスがほとんどない場合は、インデックスページを再編成および再圧縮する必要もほとんどありません。MySQL では、非圧縮データを変更することで、適切に、圧縮済みページ上のデータに削除マークを付けてから削除できるため、テーブル上の DELETE 操作は比較的効率的に行われます。

環境によっては、データのロードに要する時間がリアルタイム検索と同じくらいに重要である場合があります。特にデータウェアハウス環境では、数多くのテーブルが読み取り専用または読み取りが大半になっている可能性があります。このような場合、結果として少数のディスク読み取りとストレージコストの節約が重要である場合を除いて、ロード時間が長くなるという点で圧縮の犠牲を払うことが許容できる場合と、許容できない場合があります。

本来は、データを圧縮および圧縮解除する際に CPU 時間を使用できるときに、圧縮が最適に動作します。そのため、ワークロードが CPU バウンドではなく、I/O バウンドである場合に、圧縮を使用することで全体的なパフォーマンスを改善できることがわかるでしょう。さまざまな圧縮構成でアプリケーションのパフォーマンスをテストする際は、計画した本番システム構成と同様のプラットフォーム上でテストしてください。

構成の特性と圧縮

データベースページのディスクからの読み取りとディスクへの書き込みは、システムパフォーマンスのもっとも低速な側面です。圧縮では、CPU 時間を使用してデータを圧縮および圧縮解除することで I/O の削減が試みられるため、プロセッササイクルと比べて、I/O が比較的少ないリソースであるときに、もっとも効率性が高くなります。

多くの場合、これは特に、高速のマルチコア CPU が搭載された複数ユーザー環境で動作しているときに当てはまります。圧縮テーブルのページがメモリー内にあるときは、MySQL では多くの場合、ページの非圧縮コピー用のバッファープール内で追加のメモリー (一般に 16K バイト) が使用されます。適応型 LRU アルゴリズムでは、I/O バウンドと CPU バウンドのどちらの方式でワークロードが動作しているのかに関係なく、考慮される圧縮済みページと非圧縮ページ間でメモリー使用のバランスを調整しようと試みられます。メモリーが非常に制約されている構成よりも、バッファープール専用のメモリーがより多く搭載された構成の方が、圧縮テーブルを使用するときに適切に動作する傾向があります。

圧縮済みページサイズの選択

圧縮済みページサイズの最適な設定は、テーブルおよびそのインデックスに含まれるデータの型および分布によって異なります。圧縮済みページのサイズは、常に最大のレコードサイズよりも大きくするようにしてください。そうでなければ、Compression of B-Tree Pagesで注記したように、操作に失敗する可能性があります。

圧縮済みページサイズの設定が大きすぎると、一部の領域が無駄になりますが、頻繁にページを圧縮する必要はなくなります。圧縮済みページサイズが小さすぎると、挿入時または更新時に時間のかかる再圧縮が必要になる可能性があり、より頻繁な B ツリーノードの分割が必要になる可能性もあります。これにより、データファイルが大きくなり、インデックス作成の効率性が低くなります。

一般に、圧縮済みページサイズは 8K バイトまたは 4K バイトに設定されます。InnoDB テーブルの最大行サイズが約 8K とすれば、通常、KEY_BLOCK_SIZE=8 は安全な選択です。

14.7.4 実行時の圧縮のモニタリング

アプリケーション全体のパフォーマンス、CPU と I/O の使用率、およびディスクファイルのサイズは、アプリケーションでの圧縮の効率姓を示す適切な指標です。このセクションは、セクション14.7.3「InnoDB テーブルの圧縮の調整」に示したパフォーマンスチューニングのアドバイスに基づいて構成され、初期のテスト時には発生する可能性のない問題を見つける方法を示しています。

圧縮テーブルのパフォーマンス上の考慮事項をさらに深く掘り下げるには、例14.10「圧縮情報スキーマテーブルの使用」に記載した「情報スキーマ」テーブルを使用すれば、実行時に圧縮のパフォーマンスをモニターできます。これらのテーブルは、メモリーの内部使用および全体的に使用される圧縮の比率を反映しています。

INNODB_CMP テーブルには、使用中の圧縮済みページサイズ (KEY_BLOCK_SIZE) ごとに、圧縮アクティビティーに関する情報がレポートされます。これらのテーブル内の情報は、システム全体のものであり、データベース内のすべての圧縮テーブルにわたる圧縮の統計を集約したものです。このデータを使用すると、その他の圧縮テーブルがアクセスしていないときに、これらのテーブルを調査することでテーブルを圧縮するかどうかを決定する際に役立ちます。これには、サーバー上で比較的小さいオーバーヘッドが伴うため、圧縮失敗の全体的な効率性をチェックするために、本番環境サーバー上で定期的にクエリーを実行することがあります。

INNODB_CMP_PER_INDEX テーブルには、個別のテーブルおよびインデックスごとに、圧縮アクティビティーに関する情報がレポートされます。この情報は、圧縮の効率性を評価し、一度に 1 つのテーブルまたはインデックスのパフォーマンス問題を診断する際に、より的を絞ることができ、より役立ちます。(各 InnoDB テーブルはクラスタ化されたインデックスとして表されるため、このコンテキストでは、MySQL でテーブルとインデックス間で大きな区別が行われません。)INNODB_CMP_PER_INDEX テーブルには大量のオーバーヘッドが伴うため、さまざまなワークロード、データ、および圧縮設定の効果を分離して比較できる開発サーバーにより適しています。このモニタリングのオーバーヘッドが誤って課されることを防ぐには、INNODB_CMP_PER_INDEX テーブルのクエリーを実行する前に、innodb_cmp_per_index_enabled 構成オプションを有効にする必要があります。

考慮するべき主要な統計は、圧縮および圧縮解除操作の数、および実行に要する時間数です。B ツリーノードがいっぱいになって、変更後に圧縮済みデータを含めることができなくなると、MySQL によって B ツリーノードが分割されるため、正常な圧縮操作の数と、このような操作全体の数を比較します。INNODB_CMP および INNODB_CMP_PER_INDEX テーブル内の情報、およびアプリケーション全体のパフォーマンスとハードウェアリソースの使用率に基づいて、ハードウェア構成の変更を行なったり、バッファープールのサイズを調整したり、別のページサイズを選択したり、圧縮する別のテーブルセットを選択したりすることがあります。

圧縮および圧縮解除するために必要な CPU 時間の合計が大きい場合は、高速またはマルチコアの CPU に変更すると、同じデータ、アプリケーションのワークロード、および圧縮テーブルのセットを使用してパフォーマンスを改善する際に役立つことがあります。バッファープールのサイズを大きくすると、パフォーマンスの改善に役立つこともあります。これにより、より多くの非圧縮ページをメモリー内に滞在できるようになるため、圧縮形式でのみメモリー内に存在するページを圧縮解除する必要が少なくなります。

(アプリケーションでの INSERTUPDATE、および DELETE 操作の数、およびデータベースのサイズと比較して) 圧縮操作全体の数が大きい場合は、効率的な圧縮としては、圧縮テーブルの一部が更新される頻度が高すぎることを示している可能性があります。その場合は、より大きなページサイズを選択するか、圧縮するテーブルをより慎重に選択してください。

正常な圧縮操作の数 (COMPRESS_OPS_OK) が圧縮操作の合計数 (COMPRESS_OPS) の高い比率を占めている場合は、システムが正常に実行されている可能性が高くなります。比率が低い場合は、MySQL によって理想よりも頻繁に、B ツリーノードの再編成、再圧縮、および分割が行われます。この場合、一部のテーブルの圧縮を回避するか、圧縮テーブルの一部で KEY_BLOCK_SIZE を大きくしてください。テーブルの圧縮をオフにすると、アプリケーション内での圧縮失敗の数が合計の 1% または 2% を上回る可能性があります。(このような失敗の比率は、データのロードなどの一時的な操作時には許容範囲内である場合もあります)。

14.7.5 InnoDB テーブルでの圧縮の動作

このセクションでは、InnoDB テーブルの圧縮に関する一部の内部実装について詳細に説明します。ここで示す情報は、パフォーマンスを調整する際に役立つことがありますが、圧縮の基本的な使用を理解する必要はありません。

圧縮アルゴリズム

一部のオペレーティングシステムでは、ファイルシステムのレベルで圧縮が実装されています。一般に、ファイルは、可変サイズのブロックに圧縮される固定サイズのブロックに分割されるため、簡単に断片化されます。ブロック内部で何かが変更されるたびに、ブロック全体が再圧縮されてからディスクに書き込まれます。これらのプロパティーを使用すると、この圧縮方法が更新の多いデータベースシステムでの使用には適さなくなります。

MySQL では、LZ77 圧縮アルゴリズムが実装されている有名な zlib ライブラリの支援を得て、圧縮が実装されています。この圧縮アルゴリズムは十分に発達し、強固であり、CPU の使用率とデータサイズの削減の両方の点で効率的です。このアルゴリズムは損失なしであるため、常に、元の非圧縮データを圧縮形式から再構築できます。LZ77 圧縮は、圧縮されるデータ内で繰り返される一連のデータを見つけることで動作します。データ内の値のパターンによって、圧縮の効率性が決定されますが、多くの場合、一般的なユーザーデータは 50% 以上圧縮されます。

アプリケーションで実行される圧縮や、その他の一部のデータベース管理システムの圧縮機能とは異なり、InnoDB の圧縮は、ユーザーデータとインデックスの両方に適用されます。多くの場合、インデックスがデータベースの合計サイズの 40-50% 以上を占める可能性があるため、この相違点は重要です。データセットの圧縮が正常に動作しているときは、InnoDB のデータファイル (.idb ファイル) のサイズが非圧縮サイズの 25% - 50%、場合によってはそれよりも小さくなります。ワークロードによっては、このようにデータベースを小さくすることにより、CPU 使用率を少し増加させるだけで I/O を削減してスループットを増加できます。innodb_compression_level 構成オプションを変更すると、圧縮のレベルと CPU のオーバーヘッド間のバランスを調整できます。

InnoDB データストレージと圧縮

InnoDB テーブル内のすべてのユーザーデータは、B ツリーインデックス (クラスタ化されたインデックス) を構成しているページに格納されます。その他の一部のデータベースシステムでは、このタイプのインデックスはインデックス編成テーブルと呼ばれます。インデックスノード内の各行には、(ユーザーが指定した、またはシステムで生成された) 主キーの値およびテーブルのその他のすべてのカラムが含まれています。

InnoDB テーブル内のセカンダリインデックスは、値のペア (インデックスキーと、クラスタ化されたインデックス内の行へのポインタ) を含む B ツリーでもあります。実際は、ポインタはテーブルの主キーの値であり、インデックスキーおよび主キー以外のカラムが必要な場合に、クラスタ化されたインデックスにアクセスする際に使用されます。常に、セカンダリインデックスのレコードは、B ツリーページ上に収容される必要があります。

次のセクションで説明するように、(クラスタ化インデックスとセカンダリインデックスの両方の) B ツリーノードの圧縮は、長い VARCHARBLOB、または TEXT カラムを格納するために使用されるオーバーフローの圧縮とは異なる方法で処理されます。

B ツリーページの圧縮

B ツリーページは頻繁に更新されるため、特別な処理が必要です。B ツリーノードが分割される回数を最小限にし、それらの内容を圧縮解除および再圧縮する必要性も最小限にすることが重要となります。

MySQL で使用される技術の 1 つでは、一部のシステム情報が非圧縮形式で B ツリーノード内に保持されるため、特定のインプレース更新が容易になります。たとえば、これにより、圧縮操作なしで行に削除のマークを付け、その行を削除できます。

さらに、MySQL では、インデックスページが変更されたときに、不要な圧縮解除および再圧縮を回避しようと試みられます。システムの各 B ツリーページ内には、ページに行われた変更を記録するための非圧縮の変更ログが保持されます。小さいレコードの更新および挿入は、ページ全体を完全に再構築する必要なしで、この変更ログに書き込まれる場合があります。

変更ログ用の領域を使い果たすと、InnoDB によってページが圧縮解除され、変更が適用され、ページが再圧縮されます。再圧縮に失敗すると (圧縮の失敗と呼ばれる状況)、B ツリーノードが分割され、更新または挿入に成功するまでプロセスが繰り返されます。

OLTP アプリケーションなどで、書き込み負荷の高いワークロードでの頻繁な圧縮の失敗を回避するために、MySQL では、ページ内にいくつかの空のスペース (パディング) が予約されている場合があります。これにより、変更ログがより早く埋められ、分割を回避するための十分な空き領域がまだある間にページが再圧縮されます。各ページに残されるパディングスペースの量は、システムでページ分割の頻度が追跡されるにつれて変化します。圧縮テーブルへの書き込みが頻繁に行われる高負荷のサーバー上では、innodb_compression_failure_threshold_pct および innodb_compression_pad_pct_max 構成オプションを調整すると、このメカニズムを微調整できます。

一般に、MySQL では、InnoDB テーブル内の各 B ツリーページに 2 つ以上のレコードを収容できます。圧縮テーブルに対しては、この要件が緩和されました。B ツリーノードのリーフページには (主キーとセカンダリインデックスのどちらでも)、1 つのレコードのみが収容される必要がありますが、そのレコードはページごとの変更ログに非圧縮形式で収まる必要があります。innodb_strict_modeON の場合は、CREATE TABLE または CREATE INDEX の実行中に、MySQL によって行の最大サイズがチェックされます。行が収まらない場合は、「ERROR HY000: Too big row」というエラーメッセージが発行されます。

innodb_strict_mode が OFF のときにテーブルを作成した場合に、後続の INSERT または UPDATE ステートメントで圧縮済みページのサイズに収まらないインデックスエントリの作成が試みられると、その操作に失敗し、「ERROR 42000: Row size too large」というエラーが表示されます。(このエラーメッセージは、レコードが長すぎるインデックスの名前を示すものでも、その特定のインデックスページ上のインデックスレコードの長さや最大レコードサイズを示すものでもありません。)この問題を解決するには、ALTER TABLE を使用してテーブルを再構築し、より大きな圧縮済みページサイズ (KEY_BLOCK_SIZE) を選択して、任意のカラムプリフィクスのインデックスを短くするか、ROW_FORMAT=DYNAMIC または ROW_FORMAT=COMPACT を使用して圧縮を完全に無効にします。

BLOB、VARCHAR、および TEXT カラムの圧縮

InnoDB テーブルでは、主キーの一部ではない BLOBVARCHAR、および TEXT カラムが、個別に割り当てられたオーバーフローページに格納される場合があります。このようなカラムは、オフページカラムと呼ばれています。これらの値は、オーバーフローページの片方向リストに格納されます。

ROW_FORMAT=DYNAMIC または ROW_FORMAT=COMPRESSED で作成されたテーブルでは、カラムの長さおよび行全体の長さによっては、BLOBTEXT、または VARCHAR カラムの値が完全にオフページに格納される場合もあります。オフページに格納されるカラムでは、クラスタ化されたインデックスのレコードに、オーバーフローページへの 20 バイトのポインタのみがカラムごとに 1 つずつ含まれます。カラムがオフページに格納されるかどうかは、ページサイズおよび行の合計サイズによって異なります。行がクラスタ化されたインデックスのページ内に完全に収まらないほど長い場合は、クラスタ化されたインデックスページ上に行が収まるまで、MySQL によってオフページストレージに合った最長のカラムが選択されます。前述の注で示したように、行自体が圧縮済みページ上に収まらない場合は、エラーが発生します。

注記

ROW_FORMAT=DYNAMIC または ROW_FORMAT=COMPRESSED で作成されたテーブルでは、40 バイト以下の TEXT および BLOB カラムは、常にインラインに格納されます。

古いバージョンの MySQL で作成されたテーブルでは、ROW_FORMAT=REDUNDANTROW_FORMAT=COMPACT のみがサポートされている Antelope ファイル形式が使用されます。MySQL では、これらの形式で、クラスタ化されたインデックスレコード内に BLOBVARCHAR、および TEXT カラムの最初の 768 バイトが主キーとともに格納されます。768 バイトのプリフィクスのあとには、残りのカラム値を含むオーバーフローページへの 20 バイトのポインタが続きます。

テーブルの形式が COMPRESSED である場合は、オーバーフローページに書き込まれるすべてのデータがそのまま圧縮されます。つまり、MySQL では、データ項目全体に zlib 圧縮アルゴリズムが適用されます。圧縮済みのオーバーフローページには、データ以外では特に、ページチェックサムを構成する非圧縮のヘッダーとトレーラ、および次のオーバーフローページへのリンクが含まれます。したがって、テキストデータを使用した場合に多く見られるように、データの圧縮性が高い場合は、長い BLOBTEXT、または VARCHAR カラムで非常に大幅なストレージの節約が実現されます。一般に、JPEG などのイメージデータはすでに圧縮されているため、圧縮テーブルに格納される利点がほとんど得られません。領域の節約がほとんどない、またはまったくない場合は、二重圧縮によって CPU サイクルが無駄になる可能性があります。

オーバーフローページのサイズは、その他のページと同じです。カラムの合計長が 8K バイトのみである場合でも、オフページに格納される 10 個のカラムを含む行で、10 個のオーバーフローページが占有されます。非圧縮テーブルでは、10 個の非圧縮オーバーフローページで 160K バイトが占有されます。ページサイズが 8K の圧縮テーブルでは、80K バイトのみが占有されます。そのため、長いカラム値を含むテーブルでは、圧縮テーブル形式を使用すると効率性が高くなることが多くあります。

16K の圧縮済みページサイズを使用すると、多くの場合、このようなデータが効率的に圧縮されることで、必要なオーバーフローページが少なくなる可能性があるため、B ツリーノード自体のページ数は非圧縮形式の場合と同じであるにもかかわらず、BLOBVARCHAR、または TEXT カラムのストレージおよび I/O コストを削減できます。

圧縮と InnoDB バッファープール

圧縮済みの InnoDB テーブル (1K、2K、4、または 8K) は、16K バイト (innodb_page_size が設定されている場合は、さらに小さいサイズ) の非圧縮ページに対応しています。ページ内のデータにアクセスするために、MySQL は、圧縮済みページがバッファープール内にすでに存在しない場合、そのページをディスクから読み取ってから、その元の形式に圧縮解除します。このセクションでは、圧縮テーブルのページに関して、バッファープールが InnoDB で管理される方法について説明します。

I/O を最小限にして、ページを圧縮解除する必要性を削減するために、バッファープールに圧縮済み形式と非圧縮形式の両方のデータベースページが含まれることがあります。その他の必要なデータベースページ用の空き領域を作成するために、MySQL ではメモリー内に圧縮済みページを残しながら、バッファープールから非圧縮ページをエビクションできます。また、しばらくの間ページがアクセスされていない場合は、その他のデータ用に領域を解放するために、圧縮形式のページがディスクに書き込まれることもあります。したがって、そのときどきで、バッファープールに圧縮形式と非圧縮形式の両方のページが含まれている場合、圧縮形式のページのみが含まれている場合、どちらも含まれていない場合があります。

MySQL では、ホット (頻繁にアクセスされる) データがメモリー内に滞在する傾向となるように、最近もっとも使用されていない (LRU) リストを使用して、メモリー内に保持されるページおよび削除されるページが追跡されます。圧縮テーブルにアクセスすると、MySQL は適応型 LRU アルゴリズムを使用して、メモリー内の圧縮済みページと非圧縮ページの適切なバランスを実現します。この適応型アルゴリズムは、システムが I/O バウンドCPU バウンドのどちらの方式で実行されているかどうかの影響を受けやすくなります。この目的は、CPU の負荷が高いときにページを圧縮解除するために要する処理時間が長くなりすぎることを回避すること、および (メモリー内にすでに存在する可能性のある) 圧縮済みページを圧縮解除するために使用できる予備のサイクルが CPU に備わっているときに過剰な I/O が発生することを回避することです。システムが I/O バウンドの場合、このアルゴリズムでは、その他のディスクページ用により多くの空き領域を作成することでメモリーが常駐になるように、ページの両方のコピーではなく、非圧縮コピーを削除することが優先されます。システムが CPU バウンドの場合、MySQL では、ホットページ用に使用できるメモリーが多くなり、圧縮形式でのみメモリー内のデータを圧縮解除する必要性が少なくなるように、圧縮済みページと非圧縮ページの両方を削除することが優先されます。

圧縮と InnoDB の Redo ログファイル

圧縮済みページがデータファイルに書き込まれる前に、MySQL によってページのコピーが Redo ログに書き込まれます (最後にデータベースに書き込まれた以降に再圧縮された場合)。これは、zlib ライブラリがアップグレードされ、その変更によって圧縮済みデータとの互換性の問題が発生する可能性が低い場合でも、クラッシュリカバリ時に Redo ログを使用できるかどうかを確認するために行われます。したがって、圧縮の使用時に、ログファイルのサイズを多少大きくすること、またはより頻繁にチェックポイントを発生させる必要性を多少多くすることが要求される可能性があります。ログファイルのサイズを大きくする量またはチェックポイントの頻度を多くする数は、再構成および再圧縮が必要となる方法で圧縮済みページが変更される回数によって異なります。

圧縮テーブルでは、Redo ログおよびテーブルごとのテーブルスペースに使用されるファイル形式が MySQL 5.1 以前とは異なることに注意してください。MySQL Enterprise Backup 製品では、圧縮済み InnoDB テーブル用に、この最新の Barracuda ファイル形式がサポートされています。

14.7.6 OLTP ワークロードの圧縮

従来、InnoDB圧縮機能は、データウェアハウス構成などで、主に読み取り専用または読み取りが大半のワークロードに対して使用することが推奨されていました。高速だが、比較的小型で高価である SSD ストレージデバイスを増加すると、OLTP ワークロードでも圧縮が魅力的なものとなります。高トラフィックでインタラクティブな Web サイトでは、頻繁に INSERTUPDATE、および DELETE 操作を実行するアプリケーションで圧縮テーブルを使用することで、ストレージの要件および 1 秒あたりの I/O 操作 (IOPS) を削減できます。

MySQL 5.6 で導入された構成オプションを使用すると、書き込み負荷の高い操作のパフォーマンスおよび拡張性に重点を置いて、特定の MySQL インスタンスに合わせて圧縮の動作を調整できます。

  • innodb_compression_level を使用すると、圧縮の程度を上げたり、下げたりできます。値を大きくすると、ストレージデバイス上に収容できるデータ量が多くなりますが、圧縮時の CPU オーバーヘッドも多くなるという犠牲が伴います。値を小さくすると、ストレージ領域がクリティカルでない場合に、CPU のオーバーヘッドを削減できます。それ以外の場合は、データが特に圧縮可能でないと予測されます。

  • innodb_compression_failure_threshold_pct には、圧縮テーブルへの更新時に圧縮が失敗したときのカットオフポイントが指定されます。このしきい値を超えると、MySQL は、最大で innodb_compression_pad_pct_max で指定されたページサイズの割合まで空き領域の量を動的に調整することで、新しい各圧縮済みページ内に追加の空き領域を残し始めます。

  • innodb_compression_pad_pct_max を使用すると、ページ全体を再度圧縮する必要なしで、変更を圧縮済み行に記録するための各ページ内に予約されている領域の最大量を調整できます。値を大きくすると、ページを再度圧縮せずに記録できる変更の量が多くなります。MySQL では、実行時に指定した割合の圧縮操作に失敗したときにのみ、各圧縮テーブル内にあるページ用に可変量の空き領域が使用されますが、圧縮済みページを分割するために負荷の高い操作が必要となります。

圧縮済みデータを操作すると、圧縮済みと非圧縮の両方のバージョンのページが同時にメモリー内に保持されるため、OLTP スタイルのワークロードで圧縮を使用するときは、innodb_buffer_pool_size 構成オプションの値を大きくする準備をしてください。

14.7.7 SQL 圧縮構文の警告とエラー

Barracuda ファイル形式が有効になっていない場合に、CREATE TABLE または ALTER TABLE ステートメントで ROW_FORMAT=COMPRESSED または KEY_BLOCK_SIZE を指定すると、次のような警告が生成されます。SHOW WARNINGS ステートメントを使用すると、これらを表示できます。

レベルコードメッセージ
警告1478InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
警告1478InnoDB: KEY_BLOCK_SIZE requires innodb_file_format=1
警告1478InnoDB: ignoring KEY_BLOCK_SIZE=4.
警告1478InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
警告1478InnoDB: assuming ROW_FORMAT=COMPACT.

注:

  • デフォルトでは、これらのメッセージはエラーではなく、単なる警告です。テーブルは、オプションを指定しなかった場合と同様に、圧縮なしで作成されます。

  • innodb_strict_mode を有効にすると、MySQL では、このような場合に警告ではなく、エラーが生成されます。現在の構成では圧縮テーブルの使用が許可されていないため、テーブルは作成されません。

厳密でない動作を使用すると、ソースデータベースに圧縮テーブルが含まれていない場合でも、圧縮テーブルがサポートされていないデータベースに mysqldump ファイルをインポートできます。この場合、MySQL は操作を回避する代わりに、ROW_FORMAT=COMPACT 内にテーブルを作成します。

新しいデータベースにダンプファイルをインポートし、元のデータベース内に存在するときにテーブルが再作成されるようにするには、サーバーで innodb_file_format および innodb_file_per_table 構成パラメータが適切に設定されていることを確認します。

KEY_BLOCK_SIZE 属性は、ROW_FORMATCOMPRESSED として指定されているか、省略されている場合にのみ許可されます。その他の ROW_FORMAT とともに KEY_BLOCK_SIZE を指定すると、SHOW WARNINGS を使用して表示できる警告が生成されます。ただし、テーブルは非圧縮です。つまり、指定された KEY_BLOCK_SIZE は無視されます。

レベルコードメッセージ
警告1478 InnoDB: ignoring KEY_BLOCK_SIZE=n unless ROW_FORMAT=COMPRESSED.

innodb_strict_mode が有効になっている状態で実行している場合は、COMPRESSED 以外の任意の ROW_FORMATKEY_BLOCK_SIZE を組み合わせると警告ではなく、エラーが生成され、テーブルは作成されません。

表14.2「CREATE TABLE および ALTER TABLE オプションの意味」では、CREATE TABLE および ALTER TABLE 上でさまざまなオプションが処理される方法が要約されています。

表 14.2 CREATE TABLE および ALTER TABLE オプションの意味

オプション使用法説明
ROW_FORMAT=​REDUNDANTMySQL 5.0.3 よりも前で使用されていたストレージフォーマットROW_FORMAT=COMPACT よりも効率性が低く、下位互換性を保つためのものです。
ROW_FORMAT=​COMPACTMySQL 5.0.3 以降でのデフォルトのストレージフォーマットクラスタ化されたインデックスページに、768 バイトの長いカラム値のプリフィクスが格納され、残りのバイトはオーバーフローページに格納されます。
ROW_FORMAT=​DYNAMICinnodb_file​_format=Barracuda とともにのみ使用可能クラスタ化されたインデックスページ内に収まる場合は、そのページ内に値が保存されます。収まらない場合は、オーバーフローページへの 20 バイトのポインタのみが (プリフィクスなしで) 格納されます。
ROW_FORMAT=​COMPRESSEDinnodb_file​_format=Barracuda とともにのみ使用可能zlib を使用してテーブルおよびインデックスをデフォルトの圧縮済みページサイズの 8K バイトに圧縮します。暗黙的に ROW_FORMAT=DYNAMIC を示します。
KEY_BLOCK_​SIZE=ninnodb_file​_format=Barracuda とともにのみ使用可能1、2、4、8、または 16K バイトの圧縮済みページサイズを指定します。暗黙的に ROW_FORMAT=DYNAMIC および ROW_FORMAT=COMPRESSED を示します。

表14.3「InnoDB 厳密モードがオフになっているときの CREATE/ALTER TABLE の警告とエラー」では、CREATE TABLE または ALTER TABLE ステートメント上で、構成パラメータとオプションの特定の組み合わせで発生するエラー状況、およびオプションが SHOW TABLE STATUS の出力に表示される方法について簡単に説明しています。

innodb_strict_modeOFF の場合、MySQL によってテーブルが作成または変更されますが、次に示すように特定の設定は無視されます。警告メッセージは、MySQL エラーログで確認できます。innodb_strict_modeON の場合、このような特定のオプションの組み合わせでエラーが生成され、テーブルは作成または変更されません。エラー状況の完全な説明を参照するには、次に示すように、SHOW ERRORS ステートメントを発行します。

mysql> CREATE TABLE x (id INT PRIMARY KEY, c INT)-> ENGINE=INNODB KEY_BLOCK_SIZE=33333;ERROR 1005 (HY000): Can't create table 'test.x' (errno: 1478)
mysql> SHOW ERRORS;+-------+------+-------------------------------------------+
| Level | Code | Message |
+-------+------+-------------------------------------------+
| Error | 1478 | InnoDB: invalid KEY_BLOCK_SIZE=33333. |
| Error | 1005 | Can't create table 'test.x' (errno: 1478) |
+-------+------+-------------------------------------------+
2 rows in set (0.00 sec)

表 14.3 InnoDB 厳密モードがオフになっているときの CREATE/ALTER TABLE の警告とエラー

構文警告またはエラーの状況結果として SHOW TABLE STATUS に表示される ROW_FORMAT
ROW_FORMAT=REDUNDANTなしREDUNDANT
ROW_FORMAT=COMPACTなしCOMPACT
ROW_FORMAT=COMPRESSED または ROW_FORMAT=DYNAMIC、または KEY_BLOCK_SIZE が指定されているinnodb_file_format=Barracudainnodb_file_per_table の両方が有効になっていなければ無視されます。COMPACT
無効な KEY_BLOCK_SIZE (1、2、4、8、または 16 以外) が指定されているKEY_BLOCK_SIZE が無視されます。リクエストされたもの、または COMPACT (デフォルト)
ROW_FORMAT=COMPRESSED および有効な KEY_BLOCK_SIZE が指定されているなし。デフォルトの 8K ではなく、指定された KEY_BLOCK_SIZE が使用されます。COMPRESSED
REDUNDANTCOMPACT、または DYNAMIC 行フォーマットを使用して KEY_BLOCK_SIZE が指定されているKEY_BLOCK_SIZE が無視されます。REDUNDANTCOMPACT、または DYNAMIC
ROW_FORMATREDUNDANTCOMPACTDYNAMIC、または COMPRESSED のいずれでもないMySQL パーサーで認識される場合は無視されます。その他の場合は、エラーが発行されます。COMPACT または該当なし

innodb_strict_modeON の場合、MySQL では無効な ROW_FORMAT または KEY_BLOCK_SIZE パラメータが拒否されます。以前のバージョンの MySQL との互換性を保つために、厳密モードはデフォルトで有効になっていません。その代わりに、MySQL では、無視された無効なパラメータに対応した警告 (エラーではない) が発行されます。

SHOW TABLE STATUS を使用しても、選択した KEY_BLOCK_SIZE を表示できないことに注意してください。SHOW CREATE TABLE ステートメントでは、(テーブルの作成時に無視された場合でも) KEY_BLOCK_SIZE が表示されます。テーブルの実際の圧縮済みページサイズは、MySQL では表示できません。

14.8 InnoDB のファイル形式管理

InnoDB が進化するにつれ、新機能をサポートするために、新しいディスク上のデータ構造が必要になる場合があります。圧縮テーブル (セクション14.7「InnoDB 圧縮テーブル」を参照してください) や、オフページに格納された長い可変長カラム (セクション14.9「InnoDB の行ストレージと行フォーマット」を参照してください) などの機能には、以前のバージョンの InnoDB とは互換性のないデータファイル形式が必要です。これらのどちらの機能にも、新しい Barracuda ファイル形式の使用が必要です。

注記

その他の新機能はすべて、元の Antelope ファイル形式と互換性があるため、Barracuda ファイル形式を必要としません。

このセクションでは、新しい InnoDB テーブルのためのファイル形式の有効化、MySQL リリース間での異なるファイル形式の互換性の確認、使用されているファイル形式の識別、ファイル形式のダウングレード、および将来使用される可能性のあるファイル形式名について説明します。

指定されたファイル形式  InnoDB は、アップグレードやダウングレードの状況、または異なるレベルの MySQL を実行している異機種混在システムで互換性を管理しやすくするために、指定されたファイル形式を使用します。現在は、Antelope および Barracuda ファイル形式がサポートされています。Barracuda は最新のファイル形式です。これは、圧縮テーブルや、より効率的な BLOB ストレージのための DYNAMIC 行フォーマットなどの重要な InnoDB 機能をサポートします。以前は名前が付いていなかった元の InnoDB ファイル形式は現在、Antelope と呼ばれます。InnoDB の将来のバージョンでは、動物の名前で識別される一連のファイル形式が昇順のアルファベット順に導入される可能性があります。

14.8.1 ファイル形式の有効化

innodb_file_format 構成パラメータは、新しい InnoDB テーブルに使用するファイル形式を定義します。このパラメータは、独自のテーブルスペースを持つテーブルにのみ適用できるため、innodb_file_per_table を有効にする必要があります。

innodb_file_format パラメータは現在、Antelope および Barracuda ファイル形式をサポートしています。テーブル圧縮や新しい DYNAMIC 行フォーマットなどの、Barracuda ファイル形式によってサポートされる機能を利用する新しいテーブルを作成するには、innodb_file_formatBARRACUDA に設定します。

MySQL 5.1 以前のリリースで組み込み InnoDB がデータベースにアクセスできなくなるような、Barracuda ファイル形式によってサポートされる新機能の使用を除外するには、innodb_file_format を省略するか、またはそれを Antelope に設定します。

innodb_file_format の値は、mysqld の起動時にコマンド行で設定するか、あるいはオプションファイル my.cnf (Unix オペレーティングシステム) または my.ini (Windows) で設定できます。また、SET GLOBAL ステートメントで動的に変更することもできます。

mysql> SET GLOBAL innodb_file_format=BARRACUDA;
Query OK, 0 rows affected (0.00 sec) 

可能な場合、新しいテーブルには Barracuda 形式を使用することをお勧めしますが、MySQL 5.5 では、異なる MySQL リリースを含むレプリケーション構成との最大限の互換性のために、デフォルトのファイル形式は引き続き Antelope です。

14.8.2 ファイル形式の互換性の確認

InnoDB 1.1 には、新しいファイル形式を使用している InnoDB データファイルに対して古いリリースの MySQL サーバーを実行した場合に発生する可能性のあるクラッシュやデータ破損から保護するためのチェックがいくつか組み込まれています。これらのチェックは、サーバーが起動されたときと、テーブルに最初にアクセスしたときに実行されます。このセクションでは、これらのチェック、それらを制御する方法、および発生する可能性のあるエラーや警告の状態について説明します。

下位互換性

下位互換性の考慮事項は、最新バージョンの InnoDB (InnoDB Plugin、または InnoDB 1.1 を含む MySQL 5.5 以降) を古いバージョン (MySQL 5.1 以前、InnoDB Plugin ではなく組み込み InnoDB を含む) とともに使用している場合にのみ適用されます。互換性の問題が発生する可能性を最小限に抑えるために、MySQL 5.1 以前のすべてのデータベースサーバーを InnoDB Plugin に基づいて標準化できます。

一般に、新しいバージョンの InnoDB は、クラッシュ、ハングアップ、結果の誤り、破損などのリスクなしでは、以前のバージョンの InnoDB で安全に読み取りまたは書き込みができないテーブルまたはインデックスを作成する可能性があります。InnoDB 1.1 には、これらの状態から保護するとともに、データベースファイルや InnoDB のバージョン間での互換性の維持に役立つメカニズムが含まれています。このメカニズムを使用すると、下位互換性のないディスクファイルを作成する新機能の誤った使用を回避することによって、InnoDB リリースのいくつかの新機能 (パフォーマンス向上やバグ修正など) を利用しながら、引き続き以前のバージョンの InnoDB でデータベースを使用するオプションを保持できます。

あるバージョンの InnoDB によって特定のファイル形式がサポートされている場合は (その形式がデフォルトであるかどうかにかかわらず)、その形式または以前の形式を必要とするすべてのテーブルをクエリーして更新することができます。新機能を使用する新しいテーブルの作成だけは、有効になっている特定のファイル形式に基づいて制限されます。逆に、あるテーブルスペースに、現在実行中のソフトウェアでサポートされていないファイル形式を使用するテーブルまたはインデックスが含まれている場合は、読み取りアクセスであっても、そのテーブルスペースにはまったくアクセスできません。

InnoDB テーブルスペースを以前のファイル形式にダウングレードするには、以前の形式を使用するテーブルスペース内の新しいテーブルにデータをコピーするしか方法がありません。これは、セクション14.8.4「ファイル形式のダウングレード」で説明されている ALTER TABLE ステートメントで実行できます。

既存の InnoDB テーブルスペースのファイル形式を判定するためのもっとも簡単な方法は、SHOW TABLE STATUS コマンドを使用するか、またはテーブル INFORMATION_SCHEMA.TABLES をクエリーして、そこに含まれているテーブルのプロパティーを検査することです。テーブルの Row_format'Compressed' または 'Dynamic' としてレポートされた場合、そのテーブルを含むテーブルスペースは Barracuda 形式を使用しています。それ以外の場合は、以前の InnoDB ファイル形式である Antelope を使用しています。

内部の詳細

InnoDB のテーブルごとのテーブルスペースファイル (*.ibd ファイルによって表されます) にはすべて、ファイル形式識別子のラベルが付けられます。システムテーブルスペース (ibdata ファイルによって表されます) には、InnoDB データベースファイルのグループで使用される最高のファイル形式のタグが付けられ、そのファイルが開かれるときにこのタグがチェックされます。

圧縮テーブルを作成するか、または ROW_FORMAT=DYNAMIC でテーブルを作成すると、対応する .ibd ファイルのファイルヘッダーと InnoDB データディクショナリ内のテーブルタイプが Barracuda ファイル形式の識別子で更新されます。その時点から、このテーブルは、この新しいファイル形式をサポートしていない InnoDB のバージョンでは使用できなくなります。異常な動作から保護するために、InnoDB バージョン 5.0.21 以降では、テーブルが開かれるときに互換性チェックを実行します。

ib-file セットの定義

混乱を避けるために、この説明ではib-file セットという用語を、InnoDB が単位として管理する一連のオペレーティングシステムファイルを示すものとして定義します。ib-file セットには、次のファイルが含まれています。

  • システムテーブルスペース (1 つ以上の ibdata ファイル)。これには、内部のシステム情報 (内部のカタログや Undo 情報を含む) が含まれるほか、ユーザーデータとインデックスも含まれる可能性があります。

  • 0 個以上の単一テーブルのテーブルスペース (file per table ファイルとも呼ばれ、*.ibd ファイルという名前が付けられます)。

  • InnoDB ログファイル。通常は、ib_logfile0ib_logfile1 の 2 つです。クラッシュリカバリやバックアップに使用されます。

ib-file セットには、InnoDB テーブルに関するメタデータが含まれた、対応する .frm ファイルは含まれません。.frm ファイルは MySQL によって作成および管理され、InnoDB 内部のメタデータとの同期がとれなくなる場合があります。

1 つのib-file セットに (場合によっては複数のデータベースの) 複数のテーブルを格納できます。(MySQL では、データベースは、ほかのシステムではスキーマまたはカタログと呼ばれる、テーブルの論理的なコレクションです。)

14.8.2.1 InnoDB が起動されたときの互換性チェック

InnoDB は、ib-file セットを開いたときに発生する可能性のあるクラッシュまたはデータ破損を回避するために、その ib-file セット内で使用されているファイル形式を完全にサポートできることをチェックします。システムがクラッシュまたは高速シャットダウン (つまり、innodb_fast_shutdown が 0 より大きい) のあとに再起動された場合は、現在のソフトウェアにとっては新しすぎる形式のデータ構造 (Redo または Undo エントリや、二重書き込みページなど) がディスク上に存在する可能性があります。これらのデータ構造にアクセスすると、リカバリプロセス中に、データファイルの重大な破損が発生する場合があります。ファイル形式の起動チェックは、どのリカバリプロセスが開始されるよりも先に実行されるため、新しいテーブルとの一貫性の問題や MySQL サーバーの起動時の問題が回避されます。

バージョン InnoDB 1.0.1 から、システムテーブルスペースは、ib-file セットの一部であるいずれかのテーブルスペース内のいずれかのテーブルによって使用されている最高のファイル形式の識別子またはタグを記録します。このファイル形式タグに対するチェックは、構成パラメータ innodb_file_format_check (デフォルトでは ON) によって制御されます。

システムテーブルスペース内のファイル形式タグが、現在実行中の特定のソフトウェアによってサポートされる最高のバージョンより新しいか、または高い値であり、かつ innodb_file_format_checkON である場合は、サーバーが起動されたときに次のエラーが発行されます。

InnoDB: Error: the system tablespace is in a
file format that this version doesn't support

innodb_file_format をファイル形式名に設定することもできます。それにより、指定されたファイル形式が現在のソフトウェアでサポートされていない場合は InnoDB が起動されなくなります。また、高位境界値も指定した値に設定されます。innodb_file_format_check を設定する機能は、ib-file セット内のすべてのテーブルを手動でダウングレードする場合 に (InnoDB の将来のリリースで) 役立ちます。それにより、あとで古いバージョンの InnoDB を使用して ib-file セットにアクセスする場合は、起動時のファイル形式のチェックを使用できます。

一部の限られた状況では、サーバーを起動し、新しすぎる形式 (使用しているソフトウェアではサポートされていない形式) の ib-file セットを使用することが必要になる場合があります。構成パラメータ innodb_file_format_checkOFF に設定すると、InnoDB はデータベースを開きますが、エラーログに次の警告メッセージを発行します。

InnoDB: Warning: the system tablespace is in a
file format that this version doesn't support
注記

これによりリカバリプロセスの実行が許可され、前回のシャットダウンがクラッシュまたは高速シャットダウンであった場合はデータベースが破損する可能性があるため、これは非常に危険な設定です。innodb_file_format_checkOFF に設定するのは、前回のシャットダウンが innodb_fast_shutdown=0 で実行されたことが確実である場合だけにし、基本的にリカバリプロセスが発生しないようにしてください。将来のリリースでは、このパラメータ設定は OFF から UNSAFE に名前が変更される可能性があります。(ただし、追加のファイル形式をサポートする InnoDB の新しいリリースが公開されるまでは、起動チェックを無効にしたとしても実際には安全です。)

パラメータ innodb_file_format_check は、データベースが開かれたときの動作にのみ影響を与え、そのあとには影響を与えません。逆に、パラメータ innodb_file_format (これは、特定の形式を有効にします) は、有効になっている形式で新しいテーブルを作成できるかどうかだけを決定し、データベースを開くことができるかどうかには影響を与えません。

ファイル形式タグは高位境界値であるため、より高い形式のテーブルが作成されるか、または既存のテーブルが読み取りまたは書き込みのためにアクセスされる (その形式がサポートされていると仮定します) と、サーバーが起動されたあとに増加します。実行中のソフトウェアがサポートしている形式より高い形式の既存のテーブルにアクセスした場合は、セクション14.8.2.2「テーブルが開かれたときの互換性チェック」で説明されているように、システムテーブルスペースのタグは更新されませんが、テーブルレベルの互換性チェックが適用されます (また、エラーが発行されます)。高位境界値が更新されると常に innodb_file_format_check の値も更新されるため、コマンド SELECT @@innodb_file_format_check; では、現在開いている ib-file セット内のテーブルによって使用され、現在実行中のソフトウェアによってサポートされることがわかっている最新のファイル形式の名前が表示されます。

この動作をもっとも適切に示すために、表14.4「InnoDB データファイルの互換性および関連する InnoDB パラメータ」で説明されているシナリオを考えてみます。ある将来のバージョンの InnoDB が Cheetah 形式をサポートし、ib-file セットがそのバージョンで使用されてきたとします。

表 14.4 InnoDB データファイルの互換性および関連する InnoDB パラメータ

innodb ファイル形式のチェックinnodb ファイル形式ib-file セットで使用される最高のファイル形式InnoDB によってサポートされる最高のファイル形式結果
OFFAntelope または BarracudaBarracudaBarracudaデータベースを開くことができます。Antelope または Barracuda ファイル形式を必要とするテーブルを作成できます
OFFAntelope または BarracudaCheetahBarracudaデータベースには新しすぎる形式のファイルが含まれているため、データベースを開くと警告が表示されます。Antelope または Barracuda ファイル形式のテーブルを作成できます。Cheetah 形式のテーブルにはアクセスできません
OFFCheetahBarracudaBarracudaデータベースを開くことができません。innodb_file_format を Cheetah に設定できません
ONAntelope または BarracudaBarracudaBarracudaデータベースを開くことができます。Antelope または Barracuda ファイル形式のテーブルを作成できます
ONAntelope または BarracudaCheetahBarracudaデータベースには新しすぎる形式 (Cheetah) のファイルが含まれているため、データベースを開くことができません
ONCheetahBarracudaBarracudaデータベースを開くことができません。innodb_file_format を Cheetah に設定できません

14.8.2.2 テーブルが開かれたときの互換性チェック

テーブルがはじめてアクセスされると、InnoDB (InnoDB 1.0 の前のいくつかのリリースを含む) は、そのテーブルが格納されているテーブルスペースのファイル形式が完全にサポートされていることをチェックします。このチェックによって、チェックしないと、新しすぎるデータ構造を使用しているテーブルが検出された場合に発生するクラッシュまたは破損が回避されます。

あるリリースによってサポートされるいずれかのファイル形式を使用しているすべてのテーブルの読み取りまたは書き込みが可能です (ユーザーに十分な権限があると仮定します)。システム構成パラメータ innodb_file_format を設定すると、特定のファイル形式が特定のリリースによってサポートされている場合でも、そのファイル形式を使用する新しいテーブルが作成されるのを防ぐことができます。このような設定は下位互換性を維持するために使用される可能性がありますが、サポートされているいずれかの形式を使用するテーブルへのアクセスは防げません。

指定されたファイル形式に示されているように、5.0.21 より古いバージョンの MySQL は、テーブルが作成されるときに新しいファイル形式が使用された場合、新しいバージョンによって作成されたデータベースファイルを確実に使用することができません。さまざまなエラー状態または破損を回避するために、InnoDB は、ファイルを開くときに (たとえば、テーブルへの最初のアクセス時に) ファイル形式の互換性をチェックします。現在実行中のバージョンの InnoDB が InnoDB データディクショナリ内のテーブルタイプで識別されるファイル形式をサポートしていない場合、MySQL は次のエラーをレポートします。

ERROR 1146 (42S02): Table 'test.t1' doesn't exist

InnoDB はまた、エラーログにもメッセージを書き込みます。

InnoDB: table test/t1: unknown table type 33

このテーブルタイプは、セクション14.8.3「使用されているファイル形式の識別」で説明されている、ファイル形式のバージョンを含むテーブルスペースフラグに等しいはずです。

MySQL 4.1 の前のバージョンの InnoDB では、データベースファイルにテーブル形式の識別子が含まれていませんでした。また、MySQL 5.0.21 の前のバージョンには、テーブル形式の互換性チェックが含まれていませんでした。そのため、新しすぎる形式のテーブルが 5.0.21 の前のバージョンの InnoDB で使用されている場合、正しい動作を保証するための方法はありません。

InnoDB 1.0 以降のファイル形式管理機能 (テーブルスペースのタグ付けおよび実行時チェック) を使用すると、InnoDB は、実行中のバージョンのソフトウェアがデータベース内の既存のテーブルを正しく処理できることをできるだけ早く確認できます。

InnoDB が、サポートしていない形式のファイルを含むデータベースを開くことを (パラメータ innodb_file_format_checkOFF に設定することによって) 許可した場合も、このセクションで説明したテーブルレベルのチェックが引き続き適用されます。

InnoDB Plugin を含む MySQL 5.1 より古いリリースの InnoDB では Barracuda ファイル形式のテーブルを含むデータベースファイルを使用しないようにすることを強くお勧めします。このようなテーブルは、セクション14.8.4「ファイル形式のダウングレード」で説明されている手順を使用して Antelope 形式にダウングレードできます。

14.8.3 使用されているファイル形式の識別

innodb_file_format 構成オプションを使用して別のファイル形式を有効にした場合、その変更は新しく作成されたテーブルにのみ適用されます。また、新しいテーブルを作成した場合、そのテーブルを含むテーブルスペースには、そのテーブルの機能をサポートするために必要なもっとも早い、またはもっとも単純なファイル形式のタグが付けられます。たとえば、Barracuda ファイル形式を有効にして、Dynamic または Compressed 行フォーマットを使用しない新しいテーブルを作成した場合、そのテーブルを含む新しいテーブルスペースには Antelope ファイル形式の使用のタグが付けられます。

特定のテーブルによって使用されるファイル形式を識別することは容易です。SHOW TABLE STATUS によってレポートされた行フォーマットが Compact または Redundant である場合、このテーブルは Antelope ファイル形式を使用します。SHOW TABLE STATUS によってレポートされた行フォーマットが Compressed または Dynamic である場合、このテーブルは Barracuda ファイル形式を使用します。

mysql> SHOW TABLE STATUS\G
*************************** 1. row *************************** Name: t1 Engine: InnoDB Version: 10 Row_format: Compact Rows: 0 Avg_row_length: 0 Data_length: 16384
Max_data_length: 0 Index_length: 16384 Data_free: 0 Auto_increment: 1 Create_time: 2014-11-03 13:32:10 Update_time: NULL Check_time: NULL Collation: latin1_swedish_ci Checksum: NULL Create_options: Comment:
1 row in set (0.00 sec)

InnoDBINFORMATION_SCHEMA テーブルを使用して、特定のテーブルまたはテーブルスペースによって使用されるファイル形式を識別することもできます。例:

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test/t1'\G
*************************** 1. row *************************** TABLE_ID: 44 NAME: test/t1 FLAG: 1 N_COLS: 6 SPACE: 30 FILE_FORMAT: Antelope ROW_FORMAT: Compact
ZIP_PAGE_SIZE: 0
1 row in set (0.00 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE NAME='test/t1'\G
*************************** 1. row *************************** SPACE: 30 NAME: test/t1 FLAG: 0 FILE_FORMAT: Antelope ROW_FORMAT: Compact or Redundant PAGE_SIZE: 16384
ZIP_PAGE_SIZE: 0
1 row in set (0.00 sec)

14.8.4 ファイル形式のダウングレード

各 InnoDB テーブルスペースファイル (名前は *.ibd に一致します) には、そのテーブルとインデックスを作成するために使用されるファイル形式のタグが付けられます。テーブルスペースをダウングレードする方法として、テーブルとそのインデックスを再作成します。テーブルとそのインデックスを再作成するためのもっとも簡単な方法は、次のコマンドの使用です。

ALTER TABLE t ROW_FORMAT=COMPACT;

これを、ダウングレードする各テーブルに対して実行します。COMPACT 行フォーマットは、ファイル形式 Antelope を使用します。これは MySQL 5.0.3 で導入されました。

14.8.5 将来の InnoDB ファイル形式

MySQL 5.1 の標準の組み込み InnoDB によって使用されるファイル形式は、Antelope 形式です。InnoDB Plugin 1.0 で導入されたファイル形式は、Barracuda 形式です。追加の新しいファイル形式を必要とする新機能はまだ発表されていませんが、InnoDB ファイル形式のメカニズムでは将来の拡張が可能になっています。

完全性のために、将来のファイル形式に使用される可能性のあるファイル形式名を次に示します。Antelope、Barracuda、Cheetah、Dragon、Elk、Fox、Gazelle、Hornet、Impala、Jaguar、Kangaroo、Leopard、Moose、Nautilus、Ocelot、Porpoise、Quail、Rabbit、Shark、Tiger、Urchin、Viper、Whale、Xenops、Yak、および Zebra。これらのファイル形式は、内部の識別子 0 - 25 に対応しています。

14.9 InnoDB の行ストレージと行フォーマット

このセクションでは、テーブル圧縮や長いカラムのオフページストレージなどの特定の InnoDB 機能が、CREATE TABLE ステートメントの ROW_FORMAT 句によってどのように制御されるかについて説明します。ここでは、正しい行フォーマットを選択するための考慮事項、および MySQL リリース間の行フォーマットの互換性について説明します。

14.9.1 InnoDB 行ストレージの概要

行とそれに関連付けられたカラムのストレージが、クエリーや DML 操作のパフォーマンスに影響を与えます。1 つのディスクページに収まる行数が多いほど、クエリーやインデックスルックアップの処理は速くなり、InnoDB バッファープールで必要なキャッシュメモリーは減り、数値カラムや短い文字列カラムの更新された値を書き出すために必要な I/O も少なくなります。

各 InnoDB テーブル内のデータは、ページに分割されます。各テーブルを構成するページは、B ツリーインデックスと呼ばれるツリーデータ構造で配置されます。テーブルデータとセカンダリインデックスはどちらも、このタイプの構造を使用します。テーブル全体を表す B ツリーインデックスは、クラスタ化されたインデックスと呼ばれます。これは、主キーカラムに従って編成されます。インデックスデータ構造のノードには、その行内のすべてのカラム (クラスタ化されたインデックスの場合)、またはインデックスカラムと主キーカラム (セカンダリインデックスの場合) の値が含まれています。

可変長カラムは、このルールの例外です。B ツリーページに収めるには長すぎる BLOBVARCHAR などのカラムは、オーバーフローページと呼ばれる、個別に割り当てられたディスクページに格納されます。このようなカラムを、オフページカラムと呼びます。これらのカラムの値は、オーバーフローページの片方向リンクリストに格納され、このような各カラムには 1 つ以上のオーバーフローページの独自のリストがあります。場合によっては、ストレージの浪費を避け、また個別のページを読み取る必要をなくすために、長いカラム値のすべてまたはプリフィクスが B ツリーに格納されます。

次のセクションでは、これらの可変長カラムを表す方法を制御するために CREATE TABLE および ALTER TABLE ステートメントで使用できる句である ROW_FORMATKEY_BLOCK_SIZE について説明します。これらの句を使用するには、innodb_file_per_table および innodb_file_format 構成オプションの設定の変更も必要になる可能性があります。

14.9.2 テーブルの行フォーマットの指定

テーブルの行フォーマットは、CREATE TABLE および ALTER TABLE ステートメントの ROW_FORMAT 句で指定します。例:

CREATE TABLE t1 (f1 int unsigned) ROW_FORMAT=DYNAMIC ENGINE=INNODB; 

InnoDBROW_FORMAT オプションには、COMPACTREDUNDANTDYNAMIC、および COMPRESSED が含まれます。InnoDB テーブルの場合、デフォルトでは、行は COMPACT フォーマット (ROW_FORMAT=COMPACT) で格納されます。ROW_FORMAT テーブルオプションの詳細は、CREATE TABLE のドキュメントを参照してください。

InnoDB テーブルの物理的な行構造は、指定した ROW_FORMAT によって異なります。詳細は、セクション14.2.13.7「物理的な行構造」を参照してください。

14.9.3 DYNAMIC および COMPRESSED 行フォーマット

このセクションでは、InnoDB テーブルの DYNAMIC および COMPRESSED 行フォーマットについて説明します。これらの種類のテーブルは、innodb_file_format 構成オプションが Barracuda に設定されている場合にのみ作成できます。(Barracuda ファイル形式では、COMPACT および REDUNDANT 行フォーマットも許可されます。)

テーブルが ROW_FORMAT=DYNAMIC または ROW_FORMAT=COMPRESSED で作成された場合、長いカラム値は完全にオフページに格納され、クラスタ化されたインデックスレコードにはオーバーフローページへの 20 バイトのポインタのみが含まれます。

カラムがオフページに格納されるかどうかは、ページサイズおよび行の合計サイズによって異なります。その行が長すぎる場合は、クラスタ化されたインデックスレコードが B ツリーページに収まるまで、InnoDB はオフページストレージのもっとも長いカラムを選択します。40 バイト以下の TEXT および BLOB カラムは、常にインラインに格納されます。

DYNAMIC 行フォーマットは、(COMPACT および REDUNDANT フォーマットと同様に) 収まる場合は行全体をインデックスノード内に格納する効率性を維持しますが、この新しいフォーマットでは、長いカラムの多数のデータバイトで B ツリーノードがいっぱいになる問題が回避されます。DYNAMIC フォーマットは、長いデータ値の一部がオフページに格納される場合は通常、すべての値をオフページに格納するのがもっとも効率的であるという考え方に基づいています。DYNAMIC フォーマットでは、短いカラムは B ツリーノード内に残る可能性があるため、特定の行に必要なオーバーフローページの数が最小限に抑えられます。

COMPRESSED 行フォーマットは、オフページストレージに関して DYNAMIC 行フォーマットと同様の内部の詳細を使用するほか、追加のストレージ、圧縮されるテーブルおよびインデックスデータからのパフォーマンスの考慮事項、および小さいページサイズを使用します。COMPRESSED 行フォーマットでは、オプション KEY_BLOCK_SIZE によって、クラスタ化されたインデックスに格納されるカラムデータの量、およびオーバーフローページに配置される量が制御されます。COMPRESSED 行フォーマットの詳細は、セクション14.7「InnoDB 圧縮テーブル」を参照してください。

14.9.4 COMPACT および REDUNDANT 行フォーマット

InnoDB の早期のバージョンでは、データベースファイルに名前のないファイル形式 (現在は Antelope と呼ばれます) を使用していました。そのファイル形式では、テーブルは ROW_FORMAT=COMPACT または ROW_FORMAT=REDUNDANT で定義されます。InnoDB は、可変長カラム (BLOBVARCHAR など) の最初の 768 バイトまでを B ツリーノード内のインデックスレコードに格納し、残りの部分はオーバーフローページに格納されます。

これらの以前のバージョンとの互換性を維持するために、最新の InnoDB で作成されたテーブルは、デフォルトで COMPACT 行フォーマットになります。新しい DYNAMIC および COMPRESSED 行フォーマットについては、セクション14.9.3「DYNAMIC および COMPRESSED 行フォーマット」を参照してください。

Antelope ファイル形式では、カラムの値が 768 バイト以下の場合、オーバーフローページは必要なく、値が B ツリーノード内に格納されるために I/O がある程度削減される可能性があります。これは、比較的短い BLOB の場合に適切に機能しますが、B ツリーノードがキー値ではなくデータでいっぱいになり、それによって効率が低下する可能性があります。多数の BLOB カラムを含むテーブルでは、B ツリーノードがデータでいっぱいになり、含まれる行数が少なすぎるために、行が短い場合や、カラム値がオフページに格納される場合に比べてインデックス全体の効率が低下することがあります。

14.10 InnoDB のディスク I/O とファイル領域管理

DBA は、I/O サブシステムが飽和状態にならないようにディスク I/O を管理するとともに、ストレージデバイスがいっぱいにならないようにディスク領域を管理する必要があります。ACID 設計モデルには、冗長に見える可能性はあっても、データの信頼性の確保に役立つ、ある一定の量の I/O が必要です。これらの制約の中で、InnoDB は、ディスク I/O の量を最小限に抑えるためにデータベースの動作やディスクファイルの編成を最適化しようとします。場合によって、I/O は、データベースがビジー状態でなくなるまで、または高速シャットダウンのあとのデータベースの再起動中など、すべてを一貫性のある状態に移行することが必要になるまで延期されます。

このセクションでは、デフォルトの種類の MySQL テーブル (InnoDB テーブルとも呼ばれます) での I/O とディスク領域に関する主な考慮事項について説明します。

  • クエリーパフォーマンスを向上させるために使用されるバックグラウンド I/O の量の制御。

  • 追加の I/O を削減する代わりに耐久性を向上させる機能の有効化または無効化。

  • テーブルの、多数の小さなファイル、いくつかのより大きなファイル、またはその両方の組み合わせへの編成。

  • Redo ログファイルのサイズと、ログファイルがいっぱいになったときに発生する I/O アクティビティーとのバランス。

  • テーブルを最適なクエリーパフォーマンスのために再編成する方法。

14.10.1 InnoDB ディスク I/O

InnoDB は、可能であれば、I/O 操作を処理するための複数のスレッドを作成することによって非同期ディスク I/O を使用します。それにより、その I/O がまだ進行中の間もほかのデータベース操作を続行できるようにします。Linux および Windows プラットフォームでは、InnoDB は、使用可能な OS とライブラリ関数を使用してネイティブな非同期 I/O を実行します。その他のプラットフォームの場合も、InnoDB は引き続き I/O スレッドを使用しますが、これらのスレッドが実際には I/O 要求の完了を待つ可能性があります。この手法はシミュレートされた非同期 I/O と呼ばれます。

先読み

InnoDB は、データがすぐに必要になる可能性が高いと判断できる場合は先読み操作を実行して、そのデータをメモリー内で使用できるようにバッファープールに移動します。連続したデータに対しては、いくつかの大きな読み取り要求を作成する方が、複数の拡散した小さな要求を作成するより効率的である場合があります。InnoDB には、次の 2 つの先読みに関する経験則があります。

  • シーケンシャル先読みでは、テーブルスペース内のセグメントへのアクセスパターンがシーケンシャルであることに気付くと、InnoDB はデータベースページの読み取りのバッチを I/O システムにあらかじめ送信します。

  • ランダム先読みでは、テーブルスペース内の一部の領域がバッファープールに完全に読み取られている最中であることに気付くと、InnoDB は残りの読み取りを I/O システムに送信します。

二重書き込みバッファー

InnoDB は、二重書き込みバッファーと呼ばれる構造に関連した斬新なファイルフラッシュ手法を使用しています。これはデフォルトで有効になっています (innodb_doublewrite=ON)。これにより、クラッシュや停電のあとのリカバリの安全性が高まるだけでなく、fsync() 操作の必要性が減るため、ほとんどの種類の Unix でパフォーマンスが向上します。

データファイルにページを書き込む前に、InnoDB はまず、それらのページを二重書き込みバッファーと呼ばれる連続したテーブルスペース領域に書き込みます。二重書き込みバッファーへの書き込みとフラッシュが完了したあとにはじめて、InnoDB はそれらのページをデータファイル内の適切な位置に書き込みます。ページ書き込みの最中にオペレーティングシステム、ストレージサブシステム、または mysqld プロセスのクラッシュ (それによる破損ページの状態) が発生した場合、InnoDB は、あとでリカバリ中にそのページの正常なコピーを二重書き込みバッファーから見つけることができます。

14.10.2 ファイル領域管理

構成ファイルで定義するデータファイルによって、InnoDBシステムテーブルスペースが形成されます。これらのファイルは、テーブルスペースを形成するために論理的に連結されます。ストライピングは使用されません。現在、テーブルスペース内のどこにテーブルが割り当てられるかを定義することはできません。新しく作成されたテーブルスペースでは、InnoDB は最初のデータファイルから領域を割り当てます。

システムテーブルスペースの内部にすべてのテーブルおよびインデックスを格納することによって発生する問題を回避するために、innodb_file_per_table 構成オプションをオンにすることができます。このオプションは、新しく作成された各テーブルを個別のテーブルスペースファイル内に (拡張子 .ibd で) 格納します。この方法で格納されたテーブルの場合、ディスクファイル内の断片化は減少し、テーブルが切り捨てられると、その領域は InnoDB によって引き続きシステムテーブルスペース内に予約されるのではなく、オペレーティングシステムに返されます。

ページ、エクステント、セグメント、およびテーブルスペース

各テーブルスペースは、データベースページで構成されます。MySQL インスタンス内のテーブルスペースはすべて、同じページサイズを持っています。デフォルトでは、すべてのテーブルスペースが 16K バイトのページサイズを持っています。このページサイズを 8K バイトまたは 4K バイトに減らすには、MySQL インスタンスを作成するときに innodb_page_size オプションを指定します。

これらのページは、サイズ 1M バイトのエクステント (連続した 64 個の 16K バイトページ、128 個の 8K バイトページ、または 256 個の 4K バイトページ) にグループ化されます。InnoDB では、テーブルスペース内部のファイルセグメントと呼びます。(これらのセグメントは、実際に多数のテーブルスペースセグメントが含まれているロールバックセグメントとは異なります。)

セグメントがテーブルスペース内部で拡張される場合、InnoDB は、そのセグメントに最初の 32 ページを一度に割り当てます。そのあと、InnoDB は、そのセグメントへのすべてのエクステントの割り当てを開始します。InnoDB は、データの良好な連続性を保証するために、大きなセグメントには 1 回につき最大 4 つのエクステントを追加できます。

InnoDB では、各インデックスに 2 つのセグメントが割り当てられます。1 つは B ツリーの非リーフノード用、もう 1 つはリーフノード用です。リーフノードをディスク上で連続した状態に維持すると、これらのリーフノードには実際のテーブルデータが含まれているため、シーケンシャル I/O 操作の性能が向上します。

テーブルスペース内の一部のページにはほかのページのビットマップが含まれているため、InnoDB テーブルスペース内のいくつかのエクステントは全体としてではなく、個々のページとしてのみセグメントに割り当てることができます。

SHOW TABLE STATUS ステートメントを発行することによってテーブルスペース内の使用可能な空き領域を求めると、InnoDB は、テーブルスペース内の確実に空いているエクステントをレポートします。InnoDB は、常にいくつかのエクステントをクリーンアップやその他の内部の目的のために予約します。これらの予約されたエクステントは空き領域に含まれません。

テーブルからデータを削除すると、InnoDB は、対応する B ツリーインデックスを短くします。解放された領域をほかのユーザーが使用できるようになるかどうかは、削除のパターンがテーブルスペースに対して個々のページまたはエクステントのどちらを解放するかによって異なります。テーブルを削除したりテーブルのすべての行を削除したりすると、その領域は確実にほかのユーザーに解放されますが、それらの削除された行は、それの行がトランザクションロールバックまたは一貫性読み取りに必要なくなったあと、しばらくして自動的に発生するパージ操作によってのみ物理的に削除されることに注意してください。(セクション14.2.12「InnoDB マルチバージョン」を参照してください。)

テーブルスペースに関する情報を表示するには、テーブルスペースモニターを使用します。セクション14.15「InnoDB モニター」を参照してください。

ページのテーブル行への関連付け

可変長カラム (VARBINARYVARCHARBLOB、および TEXT) を除き、行の最大長はデータベースページの半分より少し短くなります。つまり、行の最大長は約 8000 バイトです。LONGBLOB および LONGTEXT カラムは 4G バイト未満である必要があり、BLOB および TEXT カラムを含む行全体の長さは 4G バイト未満である必要があります。

行の長さが 1 ページの半分より短い場合は、行全体がそのページ内にローカルに格納されます。それが 1 ページの半分を超える場合は、行が 1 ページの半分内に収まるまで、外部のオフページストレージとして可変長カラムが選択されます。オフページストレージとして選択されたカラムの場合、InnoDB は最初の 768 バイトをその行にローカルに格納し、残りを外部のオーバーフローページに格納します。このような各カラムには、オーバーフローページの独自のリストがあります。768 バイトのプリフィクスには、そのカラムの実際の長さを格納し、値の残りの部分が格納されているオーバーフローページリストを指す 20 バイトの値が付随します。

14.10.3 InnoDB チェックポイント

ログファイルを非常に大きくすると、チェックポイント設定中のディスク I/O が少なくなる可能性があります。ログファイルの合計サイズは多くの場合、バッファープールと同じか、またはそれより大きい設定が適切です。以前は、ログファイルが大きいとクラッシュリカバリに非常に長い時間がかかることがありましたが、MySQL 5.5 以降では、クラッシュリカバリのパフォーマンス向上により、クラッシュ後の起動を高速にして大きなログファイルを使用することが可能になっています。(厳密に言うと、このパフォーマンス向上は、InnoDB Plugin 1.0.7 以降を含む MySQL 5.1 で実現できます。この向上をデフォルトの InnoDB ストレージエンジンで実現できるのは MySQL 5.5 からです。)

チェックポイント処理の動作のしくみ

InnoDB は、ファジーチェックポイント設定と呼ばれるチェックポイントメカニズムを実装しています。InnoDB は、変更されたデータベースページをバッファープールから小さなバッチにフラッシュします。バッファープールを 1 つのバッチにフラッシュする必要はありません。それを行うと、チェックポイント設定プロセス中にユーザーの SQL ステートメントの処理が中断されます。

クラッシュリカバリ中に、InnoDB は、ログファイルに書き込まれたチェックポイントラベルを探します。それは、そのラベルの前にあるデータベースへのすべての変更がデータベースのディスクイメージ内に存在することを知っています。次に、InnoDB はそのチェックポイントから前方にログファイルをスキャンしながら、ログに記録された変更をデータベースに適用します。

14.10.4 テーブルのデフラグ

セカンダリインデックスへのランダムな挿入やセカンダリインデックスからのランダムな削除によって、インデックスが断片化される場合があります。断片化とは、ディスク上のインデックスページの物理的な順序がページ上のレコードのインデックス順序とかけ離れているか、またはインデックスに割り当てられた 64 ページのブロック内に未使用のページが多数存在することを示します。

断片化の 1 つの現象として、あるテーブルが占めている領域が、本来占めているはずの領域より大きいことがあります。それが正確にどの程度かを判定するのは困難です。InnoDB のデータとインデックスはすべて B ツリー内に格納され、それらのフィルファクタは 50% から 100% まで変動する可能性があります。断片化の別の現象として、次のようなテーブルスキャンにかかる時間が、本来かかるはずの時間より長いことがあります。

SELECT COUNT(*) FROM t WHERE non_indexed_column <> 12345;

前のクエリーでは、MySQL が、大きなテーブルに対してもっとも遅いタイプのクエリーであるフルテーブルスキャンを実行する必要があります。

インデックススキャンを高速化するために、MySQL にテーブルを再構築させる次のnullALTER TABLE 操作を定期的に実行できます。

ALTER TABLE tbl_name ENGINE=INNODB

MySQL 5.6.3 の時点では、ALTER TABLE tbl_name FORCE を使用して、テーブルを再構築するnull変更操作を実行することもできます。以前は、FORCE オプションは認識されましたが、無視されました。

MySQL 5.6.17 の時点では、ALTER TABLE tbl_name ENGINE=INNODBALTER TABLE tbl_name FORCE の両方がオンライン DDL (ALGORITHM=COPY) を使用します。詳細は、セクション14.11.1「オンライン DDL の概要」を参照してください。

デフラグ操作を実行するための別の方法として、mysqldump を使用してテーブルをテキストファイルにダンプし、テーブルを削除してから、それをダンプファイルからリロードする方法があります。

インデックスへの挿入が常に昇順であり、かつレコードが末尾からしか削除されない場合は、InnoDB のファイル領域管理アルゴリズムにより、インデックス内の断片化は発生しないことが保証されます。

14.10.5 TRUNCATE TABLE によるディスク領域の再利用

InnoDB テーブルを切り捨てるときにオペレーティングシステムのディスク領域を再利用するには、そのテーブルが独自の .ibd ファイルに格納されている必要があります。独自の .ibd ファイルに格納されるテーブルの場合は、そのテーブルを作成するときに innodb_file_per_table を有効にする必要があります。さらに、切り捨てられるテーブルとその他のテーブルの間に外部キー制約が存在していてはいけません。そうしないと、TRUNCATE TABLE 操作は失敗します。ただし、同じテーブル内の 2 つのカラム間の外部キー制約は許可されます。

テーブルが切り捨てられると、そのテーブルが削除されて新しい .ibd ファイル内に再作成され、解放された領域はオペレーティングシステムに返されます。これは、InnoDBシステムテーブルスペース内に格納されている InnoDB テーブル (innodb_file_per_table=OFF のときに作成されるテーブル) の切り捨てとは対照的です。この場合は、そのテーブルが切り捨てられたあと、解放された領域は InnoDB しか使用できません。

テーブルを切り捨て、そのディスク領域をオペレーティングシステムに返す機能はまた、物理バックアップを小さくすることもできます。システムテーブルスペースに格納されているテーブル (innodb_file_per_table=OFF のときに作成されるテーブル) の切り詰めでは、未使用領域のブロックがシステムテーブルスペース内に残されます。

14.11 InnoDB とオンライン DDL

オンライン DDL 機能は、MySQL 5.1 および MySQL 5.5 で使用可能な機能に基づいて構築されています。機能は、テーブルコピー動作を行わないように CREATE INDEXDROP INDEX を最適化しました。MySQL 5.6 で導入されたオンライン DDL 機能は、ほかのタイプの多くの ALTER TABLE 操作を、テーブルコピー、DDL が進行中の DML 操作のブロック化、またはその両方を行わないように拡張しています。

オンライン DDL 機能には、次の利点があります。

  • インデックスやカラム定義を変更する場合は常に、テーブルを数分または数時間にわたって使用できなくすることが現実的でないビジー状態の本番環境での応答性と可用性を向上させます。

  • テーブルへのアクセスを完全にブロックするか (LOCK=EXCLUSIVE 句)、クエリーを許可するが、DML は許可しないか (LOCK=SHARED 句)、またはテーブルへの完全なクエリーおよび DML アクセスを許可するか (LOCK=NONE 句) どうかを選択することによって、DDL 操作中のパフォーマンスと並列性のバランスを調整できます。LOCK 句を省略するか、または LOCK=DEFAULT を指定すると、MySQL は、操作の種類に応じてできるだけ高い並列性を許可します。

  • テーブルの新しいコピーを作成するのではなく、可能な場合はインプレースで変更を行うことによって、テーブルのコピーおよびすべてのセカンダリインデックスの再構築のためのディスク領域の使用量や I/O オーバーヘッドの一時的な増加が回避されます。

MySQL クラスタの NDB ストレージエンジンは、オンラインのテーブルスキーマ変更もサポートしていますが、InnoDB のオンライン操作に使用されるものとは互換性のない独自の構文を使用します。詳細は、セクション13.1.7.2「MySQL Cluster での ALTER TABLE オンライン操作」を参照してください。

14.11.1 オンライン DDL の概要

従来より、InnoDB テーブルでの多くの DDL 操作は高いコストを必要としました。多くの ALTER TABLE 操作は、要求されたテーブルオプションとインデックスを使用して定義された新しい空のテーブルを作成してから、既存の行を新しいテーブルに 1 つずつコピーし、行が挿入されるたびにインデックスを更新することによって機能しました。元のテーブルのすべての行がコピーされたあと、古いテーブルが削除され、そのコピーの名前が元のテーブルの名前に変更されました。

MySQL 5.5、および InnoDB Plugin を含む MySQL 5.1 は、テーブルコピー動作を行わないように CREATE INDEXDROP INDEX を最適化しました。その機能は、高速インデックス作成と呼ばれました。MySQL 5.6 は、ほかのタイプの多くの ALTER TABLE 操作を、テーブルのコピーを行わないように拡張しています。別の拡張では、テーブルが変更されている最中に SELECT クエリーや INSERTUPDATE、および DELETE (DML) ステートメントの処理を続行できるようになります。この機能の組み合わせは現在、オンライン DDL と呼ばれます。

この新しいメカニズムはまた、一般に、セカンダリインデックスなしでテーブルを作成し、データがロードされたあとにセカンダリインデックスを追加することによって、テーブルとそれに関連付けられたインデックスを作成およびロードするプロセス全体を高速化できることも示しています。

CREATE INDEX または DROP INDEX コマンドで構文の変更は必要ありませんが、この操作のパフォーマンス、領域使用量、およびセマンティクスに影響を与える要因がいくつかあります (セクション14.11.9「オンライン DDL の制限」を参照してください)。

MySQL 5.6 のオンライン DDL 拡張によって、以前はテーブルコピー、テーブルでの DML 操作のブロック、またはその両方を必要とした多くの DDL 操作が改善されます。表14.5「DDL 操作のオンラインステータスのサマリー」は、ALTER TABLE ステートメントの各種類と、オンライン DDL 機能がそれぞれにどのように適用されるかを示しています。

ALTER TABLE のパーティション化句を除き、パーティション化された InnoDB テーブルに対するオンライン DDL 操作は、通常の InnoDB テーブルに適用されるのと同じルールに従います。詳細は、セクション14.11.8「パーティション化された InnoDB テーブルに対するオンライン DDL」を参照してください。

  • インプレース?カラムは、どの操作の場合に ALGORITHM=INPLACE 句が許可されるかを示しています。推奨される値ははいです。

  • テーブルをコピー?カラムは、どの操作の場合にコストの高いテーブルコピー操作を回避できるかを示しています。推奨される値はいいえです。ALGORITHM=INPLACE は許可されるが、ある程度の量のテーブルコピーが引き続き必要な操作がいくつかある点を除き、このカラムはほぼ、インプレース?カラムの反対です。

  • 並列 DML を許可?カラムは、どの操作を完全にオンラインで実行できるかを示しています。推奨される値ははいです。DDL 中に完全な並列性が許可されることを表明するために LOCK=NONE を指定できますが、MySQL は、可能な場合は自動的にこのレベルの並列性を許可します。並列 DML が許可されている場合は、並列クエリーも常に許可されます。

  • 並列クエリーを許可?カラムは、どの DDL 操作の場合に、その操作の進行中にテーブルに対するクエリーが許可されるかを示しています。推奨される値ははいです。並列クエリーは、すべてのオンライン DDL 操作中に許可されます。これは、参考のために、すべてのセルに表示されているはいで示されています。DDL 中に並列クエリーが許可されることを表明するために LOCK=SHARED を指定できますが、MySQL は、可能な場合は自動的にこのレベルの並列性を許可します。

  • カラムは、構成オプションの設定または DDL ステートメント内のほかの句によって答えが異なる場合など、ほかのカラムのはい/いいえの値に例外がある場合はそれについて説明します。はい*いいえ*の値は、これらの追加の注によって答えが異なることを示します。

表 14.5 DDL 操作のオンラインステータスのサマリー

操作インプレース?テーブルをコピー?並列 DML を許可?並列クエリーを許可?メモ
CREATE INDEXADD INDEXはい*いいえ*はいはいFULLTEXT インデックスにはいくつかの制限があります。次の行を参照してください。現在は、作成対象の同じインデックスも同じ ALTER TABLE ステートメント内の前の句によって削除された場合、この操作はインプレースではありません (つまり、テーブルをコピーします)。
ADD FULLTEXT INDEXはいいいえ*いいえはいユーザーが指定した FTS_DOC_ID カラムがないかぎり、テーブルの最初の FULLTEXT インデックスの作成にはテーブルコピーが必要です。同じテーブル上の以降の FULLTEXT インデックスは、インプレースで作成できます。
DROP INDEXはいいいえはいはいデータファイルではなく、.frm ファイルのみを変更します。
OPTIMIZE TABLEはいはいはいはいMySQL 5.6.17 の時点では、ALGORITHM=INPLACE を使用します。old_alter_table=1 または mysqld--skip-new オプションが有効になっている場合は、ALGORITHM=COPY が使用されます。FULLTEXT インデックスを含むテーブルでは、オンライン DDL (ALGORITHM=INPLACE) を使用した OPTIMIZE TABLE はサポートされません。
カラムのデフォルト値を設定するはいいいえはいはいデータファイルではなく、.frm ファイルのみを変更します。
カラムの自動インクリメント値を変更するはいいいえはいはいデータファイルではなく、メモリーに格納された値を変更します。
外部キー制約を追加するはい*いいえ*はいはいテーブルのコピーを行わないようにするには、制約の作成中に foreign_key_checks を無効にします。
外部キー制約を削除するはいいいえはいはいforeign_key_checks オプションを有効または無効にすることができます。
カラムを名前変更するはい*いいえ*はい*はい並列 DML を許可するには、同じデータ型を維持し、カラム名のみを変更します。
カラムを追加するはいはいはい*はい自動インクリメントカラムを追加する場合は、並列 DML が許可されません。ALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
カラムを削除するはいはいはいはいALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
カラムを並べ替えるはいはいはいはいALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
ROW_FORMAT プロパティーを変更するはいはいはいはいALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
KEY_BLOCK_SIZE プロパティーを変更するはいはいはいはいALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
カラム NULL を作成するはいはいはいはいALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
カラム NOT NULL を作成するはい*はいはいはいSQL_MODEstrict_all_tables または strict_all_tables が含まれている場合は、カラムに Null が含まれていると操作は失敗します。ALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。
カラムのデータ型を変更するいいえはいいいえはい 
主キーを追加するはい*はいはいはいALGORITHM=INPLACE は許可されますが、データが大幅に再編成されるため、依然としてコストの高い操作です。カラムを NOT NULL に変換する必要がある場合は、特定の状況では ALGORITHM=INPLACE が許可されません。例14.9「主キーの作成および削除」を参照してください。
主キーを削除して別の主キーを追加するはいはいはいはいALGORITHM=INPLACE は、同じ ALTER TABLE で新しい主キーを追加する場合にのみ許可されます。データが大幅に再編成されるため、これは依然としてコストの高い操作です。
主キーを削除するいいえはいいいえはい同じ ALTER TABLE ステートメントで新しい主キーを追加することなく主キーを削除する場合は、制限が適用されます。
文字セットを変換するいいえはいいいえはい新しい文字エンコーディングが別のものである場合は、テーブルを再構築します。
文字セットを指定するいいえはいいいえはい新しい文字エンコーディングが別のものである場合は、テーブルを再構築します。
FORCE オプションを使用して再構築するはいはいはいはいMySQL 5.6.17 の時点では、ALGORITHM=INPLACE を使用します。old_alter_table=1 または mysqld--skip-new オプションが有効になっている場合は、ALGORITHM=COPY が使用されます。FULLTEXT インデックスを含むテーブルでは、オンライン DDL (ALGORITHM=INPLACE) を使用したテーブル再構築はサポートされません。
nullALTER TABLE ... ENGINE=INNODB を使用して再構築するはいはいはいはいMySQL 5.6.17 の時点では、ALGORITHM=INPLACE を使用します。old_alter_table=1 または mysqld--skip-new オプションが有効になっている場合は、ALGORITHM=COPY が使用されます。FULLTEXT インデックスを含むテーブルでは、オンライン DDL (ALGORITHM=INPLACE) を使用したテーブル再構築はサポートされません。
テーブルレベルの永続的統計オプション (STATS_PERSISTENTSTATS_AUTO_RECALCSTATS_SAMPLE_PAGES) を設定するはいいいえはいはいデータファイルではなく、.frm ファイルのみを変更します。

次の各セクションでは、並列 DML、インプレース、またはその両方で実行できる主な操作のそれぞれについて、オンライン DDL に関連した基本的な構文と使用上の注意を示します。

セカンダリインデックス

  • セカンダリインデックスを作成する: CREATE INDEX name ON table (col_list) または ALTER TABLE table ADD INDEX name (col_list)。(FULLTEXT インデックスの作成にはテーブルのロックが引き続き必要です。)

  • セカンダリインデックスを削除する: DROP INDEX name ON table; または ALTER TABLE table DROP INDEX name

InnoDB テーブルでのセカンダリインデックスの作成および削除では、MySQL 5.5 や InnoDB Plugin を含む MySQL 5.1 と同様に、テーブルコピー動作がスキップされます。

MySQL 5.6 以降では、インデックスが作成または削除されている間も、そのテーブルの読み取りおよび書き込み操作は可能なままです。CREATE INDEX または DROP INDEX ステートメントは、インデックスの初期状態にテーブルの最新の内容が反映されるように、そのテーブルにアクセスしているすべてのトランザクションが完了したあとでのみ完了します。以前は、インデックスが作成または削除されている間にテーブルを変更すると、通常はデッドロックが発生し、それによりテーブルでの INSERTUPDATE、または DELETE ステートメントが取り消されました。

カラムのプロパティー

  • カラムのデフォルト値を設定する: ALTER TABLE tbl ALTER COLUMN col SET DEFAULT literal または ALTER TABLE tbl ALTER COLUMN col DROP DEFAULT

    カラムのデフォルト値は、InnoDBデータディクショナリではなく、そのテーブルの .frm ファイルに格納されます。

  • カラムの自動インクリメント値の変更: ALTER TABLE table AUTO_INCREMENT=next_value;

    特に、レプリケーションまたはシャーディングを使用した分散システムでは、テーブルの自動インクリメントカウンタを特定の値にリセットする場合があります。テーブルに挿入された次の行は、その自動インクリメントカラムの指定された値を使用します。この手法はまた、すべてのテーブルを定期的に空にしてリロードするデータウェアハウス環境でも使用できます。それにより、自動インクリメントのシーケンスを 1 から再開できます。

  • カラムの名前変更: ALTER TABLE tbl CHANGE old_col_namenew_col_namedatatype

    同じデータ型と [NOT] NULL 属性を維持して、カラム名のみを変更する場合、この操作は常にオンラインで実行できます。

    この拡張の一部として、外部キー制約の一部であるカラムを名前変更できるようになりました。これは、以前は許可されていませんでした。外部キー定義は、新しいカラム名を使用するように自動的に更新されます。外部キーに参加しているカラムの名前変更は、ALTER TABLE のインプレースモードでのみ機能します。ALGORITHM=COPY 句を使用するか、またはその他の何らかの条件によってコマンドが内部的に ALGORITHM=COPY を使用した場合、ALTER TABLE ステートメントは失敗します。

外部キー

  • 外部キー制約の追加または削除:

    ALTER TABLE tbl1 ADD CONSTRAINT fk_name FOREIGN KEY index (col1) REFERENCES tbl2(col2) referential_actions;
    ALTER TABLE tbl DROP FOREIGN KEY fk_name;

    外部キーの削除は、foreign_key_checks オプションが有効または無効になった状態でオンラインで実行できます。外部キーをオンラインで作成するには、foreign_key_checks が無効になっている必要があります。

    特定のテーブル上の外部キー制約の名前がわからない場合は、次のステートメントを発行し、各外部キーに対する CONSTRAINT 句で制約名を見つけます。

    show create table table\G

    または、information_schema.table_constraints テーブルをクエリーし、constraint_name および constraint_type カラムを使用して外部キー名を識別します。

    この拡張の結果として、外部キーとそれに関連付けられたインデックスを 1 つのステートメントで削除することも可能になりました。これは以前、厳密な順序で並べられた個別のステートメントを必要としました。

    ALTER TABLE table DROP FOREIGN KEY constraint, DROP INDEX index;

変更されるテーブル内に外部キーがすでに存在する (つまり、そのテーブルがいずれかの FOREIGN KEY ... REFERENCE 句を含む子テーブルである) 場合は、外部キーカラムに直接関連しない操作であっても、オンライン DDL 操作には次の追加の制限が適用されます。

  • このような子テーブルでのオンライン DDL 操作中は、並列 DML が許可されません。(この制限はバグとして評価中であり、解除される可能性があります。)

  • 親テーブルが変更されたために、CASCADE または SET NULL パラメータを使用した ON UPDATE または ON DELETE 句によって子テーブル内で関連する変更が発生した場合は、子テーブルに対する ALTER TABLE が別のトランザクションのコミットも待機する可能性があります。

同様に、あるテーブルが外部キー関係にある親テーブルである場合、そこには FOREIGN KEY 句が含まれていなくても、INSERTUPDATE、または DELETE ステートメントによって子テーブル内で ON UPDATE または ON DELETE アクションが発生した場合は、そのテーブルが ALTER TABLE の完了を待機する可能性があります。

ALGORITHM=COPY に関する注意

ALGORITHM=COPY 句で実行される ALTER TABLE 操作はすべて、並列 DML 操作を妨げます。並列クエリーは、引き続き許可されます。つまり、テーブルコピー操作には常に、少なくとも LOCK=SHARED (クエリーを許可するが、DML は許可しない) の並列性の制限が含まれます。LOCK=EXCLUSIVE (DML とクエリーを妨げる) を指定することによって、このような操作の並列性をさらに制限できます。

並列 DML ではあるが、テーブルコピーが引き続き必要

その他の一部の ALTER TABLE 操作では、並列 DML は許可されますが、テーブルコピーが引き続き必要です。ただし、これらの操作のテーブルコピーは MySQL 5.5 以前の処理と比べて高速です。

  • カラムの追加、削除、または並べ替え。

  • 主キーの追加または削除。

  • テーブルの ROW_FORMAT または KEY_BLOCK_SIZE プロパティーの変更。

  • カラムの Null にできるステータスの変更。

  • OPTIMIZE TABLE

  • FORCE オプションを使用したテーブルの再構築

  • nullALTER TABLE ... ENGINE=INNODB ステートメントを使用したテーブルの再構築

注記

新しいカラム、データ型、制約、インデックスなどによってデータベーススキーマが進化するにつれ、CREATE TABLE ステートメントを最新のテーブル定義が適用されるように維持してください。オンライン DDL のパフォーマンス向上があったとしても、スキーマの一部を作成し、そのあとに ALTER TABLE ステートメントを発行するより、最初から安定したデータベース構造を作成する方が効率的です。

このガイドラインの主な例外は、多数の行を含むテーブル上のセカンダリインデックスに関するものです。通常は、セカンダリインデックスを除き、すべての詳細が指定された状態でテーブルを作成し、データをロードしてから、セカンダリインデックスを作成する方法がもっとも効率的です。初期のデータがクリーンであることがわかっていて、ロードプロセス中に一貫性チェックが必要ない場合は、外部キーでも同じ手法を使用できます (最初にデータをロードしてから、外部キーを設定します)。

CREATE TABLECREATE INDEXALTER TABLE、および同様のステートメントのどのようなシーケンスでテーブルを作成した場合でも、ステートメント SHOW CREATE TABLE table\G (正式な形式には大文字の \G が必要です) を発行することによって、現在の形式のテーブルを再構築するために必要な SQL を取得できます。この出力には、場合によっては内部的に追加され、また新しいシステム上でのテーブルのクローニングや、同一の型を持つ外部キーカラムの設定を行うときに通常であれば省略する可能性がある数値精度、NOT NULLCHARACTER SET などの句が示されます。

14.11.2 オンライン DDL でのパフォーマンスと並列性に関する考慮事項

オンライン DDL によって、パフォーマンス、並列性、可用性、スケーラビリティーなどの MySQL 操作のいくつかの側面が改善されます。

  • テーブルでのクエリーや DML 操作は DDL の進行中も処理を続行できるため、そのテーブルにアクセスするアプリケーションの応答性が向上します。MySQL サーバー全体にわたってほかのリソースのロックや待機が削減されるため、変更されるテーブルには関連しない操作であっても、スケーラビリティーの向上がもたらされます。

  • インプレース操作では、テーブルを再構築するためのディスク I/O や CPU サイクルが回避されるため、データベースにかかる全体的な負荷が最小限に抑えられるとともに、DDL 操作中に良好なパフォーマンスと高いスループットが維持されます。

  • インプレース操作では、すべてのデータがコピーされる場合に比べてバッファープールに読み取られるデータが削減されるため、以前は DDL 操作のあとの一時的なパフォーマンス低下の原因になる可能性のあった、頻繁にアクセスされるデータのメモリーからのパージが回避されます。

オンライン操作に一時ファイルが必要な場合、InnoDB はそれらのファイルを元のテーブルを含むディレクトリではなく、一時ファイルディレクトリ内に作成します。このディレクトリがそのようなファイルを保持するほどに十分に大きくない場合は、tmpdir システム変数に別のディレクトリを設定する必要があることがあります。(セクションB.5.4.4「MySQL が一時ファイルを格納する場所」を参照してください。)

オンライン DDL のロックオプション

InnoDB テーブルが DDL 操作によって変更されている間は、その操作の内部動作や ALTER TABLE ステートメントの LOCK 句に応じて、そのテーブルはロックされる場合とされない場合があります。デフォルトでは、MySQL は DDL 操作中にできるだけ少ないロックを使用します。この句は、ロックを通常の場合より制限的にする (それによって並列 DML、または DML とクエリーを制限する) ためか、またはある操作に対して何らかの期待されるレベルのロックが確実に許可されるようにするために指定します。主キーの作成または削除中に LOCK 句がその特定の種類の DDL 操作では使用できないロックのレベル (LOCK=SHAREDLOCK=NONE など) を指定している場合は、この句が表明のように機能するため、このステートメントはエラーで失敗します。次のリストは、もっとも許容的な場合からもっとも制限的な場合までの LOCK 句のさまざまな可能性を示しています。

  • LOCK=NONE を使用した DDL 操作では、クエリーと並列 DML の両方が許可されます。この句は、要求されたロックのタイプでこの種類の DDL 操作を実行できないと ALTER TABLE を失敗させるため、LOCK=NONE は、テーブルを完全に使用可能な状態に維持することが不可欠であり、かつそれができなければ DDL を取り消してもかまわない場合に指定します。たとえば、この句は、顧客のサインアップまたは購入に関連するテーブルの DDL で、コストの高い ALTER TABLE ステートメントの誤った発行によってこれらのテーブルが使用不可能にならないようにするために使用できます。

  • LOCK=SHARED を使用した DDL 操作では、テーブルへの書き込み (つまり、DML 操作) がすべてブロックされますが、そのテーブル内のデータは読み取ることができます。この句は、要求されたロックのタイプでこの種類の DDL 操作を実行できないと ALTER TABLE を失敗させるため、LOCK=SHARED は、テーブルをクエリーに対して使用可能な状態に維持することが不可欠であり、かつそれができなければ DDL を取り消してもかまわない場合に指定します。たとえば、この句は、DDL が完了するまでデータロード操作を遅らせてもかまわないが、クエリーを長時間遅らせることはできないデータウェアハウス内のテーブルの DDL で使用できます。

  • LOCK=DEFAULT を使用するか、または LOCK 句が省略された DDL 操作では、MySQL はその種類の操作で使用可能なもっとも低いレベルのロックを使用することにより、可能な場合は常に並列クエリー、DML、またはその両方を許可します。これは、そのテーブルのワークロードに基づいて可用性に関する問題が発生しないことがわかっている、事前に計画およびテストされた変更を行う場合に使用する設定です。

  • LOCK=EXCLUSIVE を使用した DDL 操作では、クエリーと DML 操作の両方がブロックされます。この句は、要求されたロックのタイプでこの種類の DDL 操作を実行できないと ALTER TABLE を失敗させるため、LOCK=EXCLUSIVE は、主な関心事が DDL を可能性のある最短の時間で完了させることであり、かつテーブルにアクセスしようとするアプリケーションを待機させてもかまわない場合に指定します。LOCK=EXCLUSIVE はまた、テーブルへの予期しないアクセスを回避するために、サーバーがアイドル状態であると想定される場合にも使用できます。

InnoDB テーブルに対するオンライン DDL ステートメントは、DDL ステートメントの準備中に短時間だけテーブルへの排他的アクセスが必要なため、そのテーブルにアクセスしている現在実行中のトランザクションがコミットまたはロールバックするのを常に待機します。同様に、完了前にも、短時間だけテーブルへの排他的アクセスが必要です。そのため、オンライン DDL ステートメントは、その DDL が完了する前に、DDL の進行中に開始され、テーブルをクエリーまたは変更するすべてのトランザクションがコミットまたはロールバックするのを待機します。

並列 DML 操作によって行われた変更を記録したあと、最後にこれらの変更を適用するにはある程度の処理が必要であるため、オンライン DDL 操作には、ほかのセッションからのテーブルアクセスをブロックする古いスタイルのメカニズムに比べて全体的に長い時間がかかる可能性があります。raw パフォーマンスの低下は、そのテーブルを使用するアプリケーションの応答性の向上とバランスがとれています。テーブル構造を変更するための理想的な手法を評価する場合は、Web ページのロード時間などの要因に基づいて、エンドユーザーのパフォーマンスの認識を考慮してください。

新しく作成された InnoDB セカンダリインデックスには、CREATE INDEX または ALTER TABLE ステートメントが実行を完了した時点でのテーブル内のコミットされたデータのみが含まれています。コミットされていない値や古いバージョンの値、または削除対象としてマークされているが、まだ古いインデックスから削除されていない値は含まれていません。

インプレース DDL 操作とテーブルコピー DDL 操作のパフォーマンスの比較

オンライン DDL 操作の raw パフォーマンスは、その操作がインプレースで実行されるか、またはテーブル全体のコピーと再構築が必要かによってほとんど決定されます。インプレースで実行できる操作の種類や、テーブルコピー操作を行わないための何らかの要件を確認するには、表14.5「DDL 操作のオンラインステータスのサマリー」を参照してください。

インプレース DDL のパフォーマンス向上は、主キーのインデックスではなく、セカンダリインデックスに対する操作に適用されます。InnoDB テーブルの行は、主キーに基づいて編成されたクラスタ化されたインデックスに格納されます。これにより、一部のデータベースシステムでインデックス編成テーブルと呼ばれるものが形成されます。このテーブル構造は主キーにきわめて密接に結び付けられているため、主キーの再定義にはデータのコピーが引き続き必要です。

主キーに対する操作で ALGORITHM=INPLACE が使用される場合は、データが引き続きコピーされるにもかかわらず、次の理由で ALGORITHM=COPY を使用するより効率的です。

  • ALGORITHM=INPLACE には、Undo ロギングやそれに関連する Redo ロギングが必要ありません。これらの操作は、ALGORITHM=COPY を使用する DDL ステートメントのオーバーヘッドを増やします。

  • セカンダリインデックスエントリは事前にソートされているため、順番にロードできます。

  • セカンダリインデックスへのランダムアクセス挿入は存在しないため、変更バッファーは使用されません。

オンライン DDL 操作の相対的なパフォーマンスを評価するには、現在のバージョンと以前のバージョンの MySQL を使用して、このような操作を大きな InnoDB テーブルで実行できます。また、すべてのパフォーマンステストを最新の MySQL バージョンで実行することもできます。つまり、old_alter_table システム変数を設定することにより、以前の DDL 動作をシミュレートして前の結果を求めます。セッション内でステートメント set old_alter_table=1 を発行し、DDL パフォーマンスを測定して前の数値を記録します。次に、set old_alter_table=0 を発行して新しい、高速な動作を再度有効にし、DDL 操作を再度実行してあとの数値を記録します。

DDL 操作がその変更をインプレースで行うか、またはテーブルコピーを実行するかの基本的な考え方については、コマンドが完了したあとに表示されるrows affectedの値を見てください。たとえば、さまざまなタイプの DDL 操作を実行したあとに表示される可能性のある行を次に示します。

  • カラムのデフォルト値の変更 (非常に高速であり、テーブルデータにはまったく影響を与えません):

    Query OK, 0 rows affected (0.07 sec)
  • インデックスの追加 (時間はかかりますが、0 rows affected はテーブルがコピーされないことを示しています):

    Query OK, 0 rows affected (21.42 sec)
  • カラムのデータ型の変更 (かなりの時間がかかり、テーブルのすべての行の再構築が必要です):

    Query OK, 1671168 rows affected (1 min 35.54 sec)

たとえば、大きなテーブルで DDL 操作を実行する前に、その操作が速いか遅いかを次のようにチェックできます。

  1. テーブル構造をクローニングします。

  2. クローニングされたテーブルに非常に少量のデータを移入します。

  3. クローニングされたテーブルで DDL 操作を実行します。

  4. rows affectedの値が 0 かどうかをチェックします。0 以外の値は、この操作にはテーブル全体の再構築が必要なため、特別な計画が必要になる可能性があることを示します。たとえば、この DDL 操作をスケジュールされたダウンタイムの期間中に、または各レプリケーションスレーブサーバー上で一度に 1 つずつ実行することができます。

MySQL 処理の削減をより深く理解するには、DDL 操作の前後に InnoDB に関連した performance_schema および INFORMATION_SCHEMA テーブルを検査して、物理的な読み取り、書き込み、メモリー割り当てなどの数を確認します。

14.11.3 オンライン DDL の SQL 構文

通常、InnoDB テーブルに対して ALTER TABLE ステートメントを使用する場合、オンライン DDL を有効にするために特殊なことをする必要はありません。インプレースで実行できるか、並列 DML を許可するか、またはその両方の DDL 操作の種類については、表14.5「DDL 操作のオンラインステータスのサマリー」を参照してください。一部の種類には、構成設定または ALTER TABLE 句の特定の組み合わせが必要になります。

ALTER TABLE ステートメントの LOCK および ALGORITHM 句を使用することによって、特定のオンライン DDL 操作のさまざまな側面を制御できます。これらの句はステートメントの最後に現れ、テーブルやカラムの指定とはカンマで区切られます。LOCK 句は、テーブルへの並列アクセスの程度を微調整するのに役立ちます。ALGORITHM 句は、主にパフォーマンス比較を目的にしているほか、既存の DDL コードで何らかの問題が発生した場合の古いテーブルコピー動作へのフォールバックとしても使用されます。例:

  • テーブルの読み取り、書き込み、またはその両方を誤って不可能にしてしまうことがないようにするには、ALTER TABLE ステートメントで LOCK=NONE (読み取りと書き込みの両方を許可する) や LOCK=SHARED (読み取りを許可する) などの句を指定できます。要求されたレベルの並列性が使用できない場合、操作はただちに停止します。

  • パフォーマンスを比較するには、old_alter_table 構成オプションを設定する代わりに、1 つのステートメントを ALGORITHM=INPLACE で、もう 1 つのステートメントを ALGORITHM=COPY で実行できます。

  • テーブルをコピーした ALTER TABLE を実行することによってサーバーが結合されてしまう可能性をなくすには、インプレースメカニズムを使用できなければステートメントがただちに停止するように ALGORITHM=INPLACE を含めることができます。インプレースで実行できるか、またはできない DDL 操作のリストについては、表14.5「DDL 操作のオンラインステータスのサマリー」を参照してください。

LOCK 句の詳細は、セクション14.11.2「オンライン DDL でのパフォーマンスと並列性に関する考慮事項」を参照してください。オンライン DDL の使用の完全な例については、セクション14.11.5「オンライン DDL の例」を参照してください。

14.11.4 DDL ステートメントの結合または分離

オンライン DDL が導入される前は、多くの DDL 操作を 1 つの ALTER TABLE ステートメントに結合することが一般的な習慣でした。各 ALTER TABLE ステートメントにはテーブルのコピーと再構築が含まれていたため、テーブルに対するすべての変更を 1 回の再構築操作で実行できたことから、同じテーブルへのいくつかの変更を一度に行う方が効率的でした。マイナス面としては、DDL 操作に関連する SQL コードが保守しにくく、別のスクリプトでの再利用も難しい点がありました。特定の変更が毎回異なっていたとすると、少し異なるシナリオごとに、新しい複雑な ALTER TABLE の構築が必要になる可能性があります。

インプレースで実行できる DDL 操作の場合は、表14.5「DDL 操作のオンラインステータスのサマリー」に示すように、効率を犠牲にすることなく、スクリプト作成や保守を容易にするために DDL 操作を個々の ALTER TABLE ステートメントに分離できるようになりました。たとえば、次のような複雑なステートメントを取り上げ、

alter table t1 add index i1(c1), add unique index i2(c2), change c4_old_name c4_new_name integer unsigned;

それを独立してテストおよび実行できる、次のようなより簡単な部分に分解することができます。

alter table t1 add index i1(c1);
alter table t1 add unique index i2(c2);
alter table t1 change c4_old_name c4_new_name integer unsigned not null;

複数の部分からなる ALTER TABLE ステートメントは、次の目的に引き続き使用できます。

  • 特定のシーケンスで実行する必要のある操作。たとえば、インデックスの作成に続けて、そのインデックスを使用する外部キー制約を作成する場合など。

  • グループとして成功または失敗するようにしたい、すべてが同じ特定の LOCK 句を使用している操作。

  • インプレースで実行できない、つまり、引き続きテーブルをコピーして再構築する操作。

  • 特殊なシナリオでの正確な下位互換性のために必要な場合に強制的にテーブルコピー動作を行うために、ALGORITHM=COPY または old_alter_table=1 を指定する操作。

14.11.5 オンライン DDL の例

次の各コード例は、そのパフォーマンス、並列性、およびスケーラビリティーが最新のオンライン DDL 拡張によって向上したいくつかの操作を示しています。

例 14.1 オンライン DDL 実験のためのスキーマ設定コード

これらのデモで使用される初期のテーブルを設定するコードを次に示します。

set autocommit = 0;
set foreign_key_checks = 1;
set global innodb_file_per_table = 1;
set old_alter_table=0;
prompt mysql:
use test;
\! echo "Setting up 'small' table:"
drop table if exists small_table;
create table small_table as select * from information_schema.columns;
alter table small_table add id int unsigned not null primary key auto_increment;
select count(id) from small_table;
\! echo "Setting up 'big' table:"
drop table if exists big_table;
create table big_table as select * from information_schema.columns;
show create table big_table\G
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
commit;
alter table big_table add id int unsigned not null primary key auto_increment;
select count(id) from big_table;

このコードを実行すると、簡略化のために圧縮され、もっとも重要な点が太字で示された次の出力が得られます。

Setting up 'small' table:
Query OK, 0 rows affected (0.01 sec)
Query OK, 1678 rows affected (0.13 sec)
Records: 1678 Duplicates: 0 Warnings: 0
Query OK, 1678 rows affected (0.07 sec)
Records: 1678 Duplicates: 0 Warnings: 0
+-----------+
| count(id) |
+-----------+
| 1678 |
+-----------+
1 row in set (0.00 sec)
Setting up 'big' table:
Query OK, 0 rows affected (0.16 sec)
Query OK, 1678 rows affected (0.17 sec)
Records: 1678 Duplicates: 0 Warnings: 0
*************************** 1. row *************************** Table: big_table
Create Table: CREATE TABLE `big_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Query OK, 1678 rows affected (0.09 sec)
Records: 1678 Duplicates: 0 Warnings: 0
Query OK, 3356 rows affected (0.07 sec)
Records: 3356 Duplicates: 0 Warnings: 0
Query OK, 6712 rows affected (0.17 sec)
Records: 6712 Duplicates: 0 Warnings: 0
Query OK, 13424 rows affected (0.44 sec)
Records: 13424 Duplicates: 0 Warnings: 0
Query OK, 26848 rows affected (0.63 sec)
Records: 26848 Duplicates: 0 Warnings: 0
Query OK, 53696 rows affected (1.72 sec)
Records: 53696 Duplicates: 0 Warnings: 0
Query OK, 107392 rows affected (3.02 sec)
Records: 107392 Duplicates: 0 Warnings: 0
Query OK, 214784 rows affected (6.28 sec)
Records: 214784 Duplicates: 0 Warnings: 0
Query OK, 429568 rows affected (13.25 sec)
Records: 429568 Duplicates: 0 Warnings: 0
Query OK, 859136 rows affected (28.16 sec)
Records: 859136 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.03 sec)
Query OK, 1718272 rows affected (1 min 9.22 sec)
Records: 1718272 Duplicates: 0 Warnings: 0
+-----------+
| count(id) |
+-----------+
| 1718272 |
+-----------+
1 row in set (1.75 sec)

例 14.2 CREATE INDEX および DROP INDEX の速度と効率

次のステートメントシーケンスは、CREATE INDEX および DROP INDEX ステートメントの相対的な速度を示しています。小さなテーブルの場合は、速い方法と遅い方法のどちらを使用しても経過時間は 1 秒未満であるため、rows affectedの出力を見て、どちらの操作がテーブル再構築を回避できるかを確認します。大きなテーブルの場合は、テーブル再構築のスキップによってかなりの時間が節約されるため、効率の違いは明らかです。

\! clear
\! echo "=== Create and drop index (small table, new/fast technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/small_table.ibd
create index i_dtyp_small on small_table (data_type), algorithm=inplace;
\! echo "Data size after index created: "
\! du -k data/test/small_table.ibd
drop index i_dtyp_small on small_table, algorithm=inplace;
-- Compare against the older slower DDL.
\! echo "=== Create and drop index (small table, old/slow technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/small_table.ibd
create index i_dtyp_small on small_table (data_type), algorithm=copy;
\! echo "Data size after index created: "
\! du -k data/test/small_table.ibd
drop index i_dtyp_small on small_table, algorithm=copy;
-- In the above example, we examined the "rows affected" number,
-- ideally looking for a zero figure. Let's try again with a larger
-- sample size, where we'll see that the actual time taken can
-- vary significantly.
\! echo "=== Create and drop index (big table, new/fast technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/big_table.ibd
create index i_dtyp_big on big_table (data_type), algorithm=inplace;
\! echo "Data size after index created: "
\! du -k data/test/big_table.ibd
drop index i_dtyp_big on big_table, algorithm=inplace;
\! echo "=== Create and drop index (big table, old/slow technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/big_table.ibd
create index i_dtyp_big on big_table (data_type), algorithm=copy;
\! echo "Data size after index created: "
\! du -k data/test/big_table.ibd
drop index i_dtyp_big on big_table, algorithm=copy;

このコードを実行すると、簡略化のために圧縮され、もっとも重要な点が太字で示された次の出力が得られます。

Query OK, 0 rows affected (0.00 sec)
=== Create and drop index (small table, new/fast technique) ===
Data size (kilobytes) before index created:
384 data/test/small_table.ibd
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
Data size after index created:
432 data/test/small_table.ibd
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
=== Create and drop index (small table, old/slow technique) ===
Data size (kilobytes) before index created:
432 data/test/small_table.ibd
Query OK, 1678 rows affected (0.12 sec)
Records: 1678 Duplicates: 0 Warnings: 0
Data size after index created:
448 data/test/small_table.ibd
Query OK, 1678 rows affected (0.10 sec)
Records: 1678 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
=== Create and drop index (big table, new/fast technique) ===
Data size (kilobytes) before index created:
315392 data/test/big_table.ibd
Query OK, 0 rows affected (33.32 sec)
Records: 0 Duplicates: 0 Warnings: 0
Data size after index created:
335872 data/test/big_table.ibd
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
=== Create and drop index (big table, old/slow technique) ===
Data size (kilobytes) before index created:
335872 data/test/big_table.ibd
Query OK, 1718272 rows affected (1 min 5.01 sec)
Records: 1718272 Duplicates: 0 Warnings: 0
Data size after index created:
348160 data/test/big_table.ibd
Query OK, 1718272 rows affected (46.59 sec)
Records: 1718272 Duplicates: 0 Warnings: 0

例 14.3 CREATE INDEX および DROP INDEX 中の並列 DML

CREATE INDEX および DROP INDEX と同時に実行されている DML ステートメント (挿入、更新、または削除) を示すために、次に、同じデータベースに接続された個別の mysql セッションで実行したいくつかのコードスニペットを示します。

-- We'll run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.
use test;
create index i_concurrent on big_table(table_name);
-- We'll run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.
use test;
drop index i_concurrent on big_table;
-- We'll run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.
-- In our test instance, that column has about 1.7M rows, with 136 different values.
-- Sample values: COLUMNS (20480), ENGINES (6144), EVENTS (24576), FILES (38912), TABLES (21504), VIEWS (10240).
set autocommit = 0;
use test;
select distinct character_set_name from big_table where table_name = 'FILES';
delete from big_table where table_name = 'FILES';
select distinct character_set_name from big_table where table_name = 'FILES';
-- I'll issue the final rollback interactively, not via script,
-- the better to control the timing.
-- rollback;

このコードを実行すると、簡略化のために圧縮され、もっとも重要な点が太字で示された次の出力が得られます。

mysql: source concurrent_ddl_create.sql
Database changed
Query OK, 0 rows affected (1 min 25.15 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql: source concurrent_ddl_drop.sql
Database changed
Query OK, 0 rows affected (24.98 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql: source concurrent_dml.sql
Query OK, 0 rows affected (0.00 sec)
Database changed
+--------------------+
| character_set_name |
+--------------------+
| NULL |
| utf8 |
+--------------------+
2 rows in set (0.32 sec)
Query OK, 38912 rows affected (1.84 sec)
Empty set (0.01 sec)
mysql: rollback;
Query OK, 0 rows affected (1.05 sec)

例 14.4 カラムの名前変更

ALTER TABLE を使用したカラムの名前変更のデモを次に示します。新しい、高速な DDL メカニズムを使用して名前を変更してから、古い、低速な DDL メカニズムを (old_alter_table=1 とともに) 使用して元のカラム名をリストアします。

注:

  • カラムの名前変更の構文にはデータ型の再指定も含まれるため、コストの高いテーブル再構築を回避するために、まったく同じデータ型を指定するよう十分に注意してください。この場合は、show create table table\G の出力をチェックし、元のカラム定義から CHARACTER SETNOT NULL などの句をすべてコピーしました。

  • この場合も、小さなテーブルのカラムの名前変更は十分高速であるため、新しい DDL メカニズムが古いメカニズムより効率的であることを確認するには rows affected の数値を検査する必要があります。大きなテーブルでは、経過時間の違いによって速度の向上が明らかになります。

\! clear
\! echo "Rename column (fast technique, small table):"
alter table small_table change `IS_NULLABLE` `NULLABLE` varchar(3) character set utf8 not null, algorithm=inplace;
\! echo "Rename back to original name (slow technique):"
alter table small_table change `NULLABLE` `IS_NULLABLE` varchar(3) character set utf8 not null, algorithm=copy;
\! echo "Rename column (fast technique, big table):"
alter table big_table change `IS_NULLABLE` `NULLABLE` varchar(3) character set utf8 not null, algorithm=inplace;
\! echo "Rename back to original name (slow technique):"
alter table big_table change `NULLABLE` `IS_NULLABLE` varchar(3) character set utf8 not null, algorithm=copy;

このコードを実行すると、簡略化のために圧縮され、もっとも重要な点が太字で示された次の出力が得られます。

Rename column (fast technique, small table):
Query OK, 0 rows affected (0.05 sec)
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0
Rename back to original name (slow technique):
Query OK, 0 rows affected (0.00 sec)
Query OK, 1678 rows affected (0.35 sec)
Records: 1678 Duplicates: 0 Warnings: 0
Rename column (fast technique, big table):
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.11 sec)
Records: 0 Duplicates: 0 Warnings: 0
Rename back to original name (slow technique):
Query OK, 0 rows affected (0.00 sec)
Query OK, 1718272 rows affected (1 min 0.00 sec)
Records: 1718272 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)

例 14.5 外部キーの削除

外部キーのデモ (外部キー制約の削除の速度の向上を含む) を次に示します。

\! clear
-- Make sure foreign keys are being enforced, and allow
-- rollback after doing some DELETEs that affect both
-- parent and child tables.
set foreign_key_checks = 1;
set autocommit = 0;
-- Create a parent table, containing values that we know are already present
-- in the child tables.
drop table if exists schema_names;
create table schema_names (id int unsigned not null primary key auto_increment, schema_name varchar(64) character set utf8 not null, index i_schema (schema_name)) as select distinct table_schema schema_name from small_table;
show create table schema_names\G
show create table small_table\G
show create table big_table\G
-- Creating the foreign key constraint still involves a table rebuild when foreign_key_checks=1,
-- as illustrated by the "rows affected" figure.
alter table small_table add constraint small_fk foreign key i_table_schema (table_schema) references schema_names(schema_name) on delete cascade;
alter table big_table add constraint big_fk foreign key i_table_schema (table_schema) references schema_names(schema_name) on delete cascade;
show create table small_table\G
show create table big_table\G
select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table group by table_schema;
select count(table_schema) howmany, table_schema from big_table group by table_schema;
-- big_table is the parent table.
-- schema_names is the parent table.
-- big_table is the child table.
-- (One row in the parent table can have many "children" in the child table.)
-- Changes to the parent table can ripple through to the child table.
-- For example, removing the value 'test' from schema_names.schema_name will
-- result in the removal of 20K or so rows from big_table.
delete from schema_names where schema_name = 'test';
select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table group by table_schema;
select count(table_schema) howmany, table_schema from big_table group by table_schema;
-- Because we've turned off autocommit, we can still get back those deleted rows
-- if the DELETE was issued by mistake.
rollback;
select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table group by table_schema;
select count(table_schema) howmany, table_schema from big_table group by table_schema;
-- All of the cross-checking between parent and child tables would be
-- deadly slow if there wasn't the requirement for the corresponding
-- columns to be indexed!
-- But we can get rid of the foreign key using a fast operation
-- that doesn't rebuild the table.
-- If we didn't specify a constraint name when setting up the foreign key, we would
-- have to find the auto-generated name such as 'big_table_ibfk_1' in the
-- output from 'show create table'.
-- For the small table, we'll drop the foreign key and the associated index.
-- Having an index on a small table is less critical.
\! echo "DROP FOREIGN KEY and INDEX from small_table:"
alter table small_table drop foreign key small_fk, drop index small_fk;
-- For the big table, we'll drop the foreign key and leave the associated index.
-- If we are still doing queries that reference the indexed column, the index is
-- very important to avoid a full table scan of the big table.
\! echo "DROP FOREIGN KEY from big_table:"
alter table big_table drop foreign key big_fk;
show create table small_table\G
show create table big_table\G

このコードを実行すると、簡略化のために圧縮され、もっとも重要な点が太字で示された次の出力が得られます。

Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 4 rows affected (0.03 sec)
Records: 4 Duplicates: 0 Warnings: 0
*************************** 1. row *************************** Table: schema_names
Create Table: CREATE TABLE `schema_names` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL, PRIMARY KEY (`id`), KEY `i_schema` (`schema_name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
*************************** 1. row *************************** Table: small_table
Create Table: CREATE TABLE `small_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL, `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
*************************** 1. row *************************** Table: big_table
Create Table: CREATE TABLE `big_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL, `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `big_fk` (`TABLE_SCHEMA`)
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Query OK, 1678 rows affected (0.10 sec)
Records: 1678 Duplicates: 0 Warnings: 0
Query OK, 1718272 rows affected (1 min 14.54 sec)
Records: 1718272 Duplicates: 0 Warnings: 0
*************************** 1. row *************************** Table: small_table
Create Table: CREATE TABLE `small_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL, `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `small_fk` (`TABLE_SCHEMA`),CONSTRAINT `small_fk` FOREIGN KEY (`TABLE_SCHEMA`) REFERENCES `schema_names` (`schema_name`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.12 sec)
*************************** 1. row *************************** Table: big_table
Create Table: CREATE TABLE `big_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL, `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `big_fk` (`TABLE_SCHEMA`),CONSTRAINT `big_fk` FOREIGN KEY (`TABLE_SCHEMA`) REFERENCES `schema_names` (`schema_name`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.01 sec)
+--------------------+
| schema_name |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
+---------+--------------------+
| howmany | table_schema |
+---------+--------------------+
| 563 | information_schema |
| 286 | mysql |
| 786 | performance_schema |
| 43 | test |
+---------+--------------------+
4 rows in set (0.01 sec)
+---------+--------------------+
| howmany | table_schema |
+---------+--------------------+
| 576512 | information_schema |
| 292864 | mysql |
| 804864 | performance_schema |
| 44032 | test |
+---------+--------------------+
4 rows in set (2.10 sec)
Query OK, 1 row affected (1.52 sec)
+--------------------+
| schema_name |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
+---------+--------------------+
| howmany | table_schema |
+---------+--------------------+
| 563 | information_schema |
| 286 | mysql |
| 786 | performance_schema |
+---------+--------------------+
3 rows in set (0.00 sec)
+---------+--------------------+
| howmany | table_schema |
+---------+--------------------+
| 576512 | information_schema |
| 292864 | mysql |
| 804864 | performance_schema |
+---------+--------------------+
3 rows in set (1.74 sec)
Query OK, 0 rows affected (0.60 sec)
+--------------------+
| schema_name |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)
+---------+--------------------+
| howmany | table_schema |
+---------+--------------------+
| 563 | information_schema |
| 286 | mysql |
| 786 | performance_schema |
| 43 | test |
+---------+--------------------+
4 rows in set (0.01 sec)
+---------+--------------------+
| howmany | table_schema |
+---------+--------------------+
| 576512 | information_schema |
| 292864 | mysql |
| 804864 | performance_schema |
| 44032 | test |
+---------+--------------------+
4 rows in set (1.59 sec)
DROP FOREIGN KEY and INDEX from small_table:
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
DROP FOREIGN KEY from big_table:
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
*************************** 1. row *************************** Table: small_table
Create Table: CREATE TABLE `small_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL, `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
*************************** 1. row *************************** Table: big_table
Create Table: CREATE TABLE `big_table` ( `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0', `COLUMN_DEFAULT` longtext CHARACTER SET utf8, `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL, `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL, `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL, `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL, `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL, `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL, `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL, `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL, `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '', `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '', `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '', `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '', `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `big_fk` (`TABLE_SCHEMA`)
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

例 14.6 自動インクリメント値の変更

テーブルカラムの自動インクリメントの下限値を増やすコードを次に示します。これは、この操作によってテーブル再構築がどのように回避されているか、さらには InnoDB の自動インクリメントカラムに関する興味深いその他のいくつかの事実を示しています。

\! clear
\! echo "=== Adjusting the Auto-Increment Limit for a Table ==="
\! echo
drop table if exists schema_names;
create table schema_names (id int unsigned not null primary key auto_increment, schema_name varchar(64) character set utf8 not null, index i_schema (schema_name)) as select distinct table_schema schema_name from small_table;
\! echo "Initial state of schema_names table. AUTO_INCREMENT is included in SHOW CREATE TABLE output."
\! echo "Note how MySQL reserved a block of IDs, but only needed 4 of them in this transaction, so the next inserted values would get IDs 8 and 9."
show create table schema_names\G
select * from schema_names order by id;
\! echo "Inserting even a tiny amount of data can produce gaps in the ID sequence."
insert into schema_names (schema_name) values ('eight'), ('nine');
\! echo "Bumping auto-increment lower limit to 20 (fast mechanism):"
alter table schema_names auto_increment=20, algorithm=inplace;
\! echo "Inserting 2 rows that should get IDs 20 and 21:"
insert into schema_names (schema_name) values ('foo'), ('bar');
commit;
\! echo "Bumping auto-increment lower limit to 30 (slow mechanism):"
alter table schema_names auto_increment=30, algorithm=copy;
\! echo "Inserting 2 rows that should get IDs 30 and 31:"
insert into schema_names (schema_name) values ('bletch'),('baz');
commit;
select * from schema_names order by id;
\! echo "Final state of schema_names table. AUTO_INCREMENT value shows the next inserted row would get ID=32."
show create table schema_names\G

このコードを実行すると、簡略化のために圧縮され、もっとも重要な点が太字で示された次の出力が得られます。

=== Adjusting the Auto-Increment Limit for a Table ===
Query OK, 0 rows affected (0.01 sec)
Query OK, 4 rows affected (0.02 sec)
Records: 4 Duplicates: 0 Warnings: 0
Initial state of schema_names table. AUTO_INCREMENT is included in SHOW CREATE TABLE output.
Note how MySQL reserved a block of IDs, but only needed 4 of them in this transaction, so the next inserted values would get IDs 8 and 9.
*************************** 1. row *************************** Table: schema_names
Create Table: CREATE TABLE `schema_names` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL, PRIMARY KEY (`id`), KEY `i_schema` (`schema_name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
+----+--------------------+
| id | schema_name |
+----+--------------------+
| 1 | information_schema |
| 2 | mysql |
| 3 | performance_schema |
| 4 | test |
+----+--------------------+
4 rows in set (0.00 sec)
Inserting even a tiny amount of data can produce gaps in the ID sequence.
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
Bumping auto-increment lower limit to 20 (fast mechanism):
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
Inserting 2 rows that should get IDs 20 and 21:
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Bumping auto-increment lower limit to 30 (slow mechanism):
Query OK, 8 rows affected (0.02 sec)
Records: 8 Duplicates: 0 Warnings: 0
Inserting 2 rows that should get IDs 30 and 31:
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.01 sec)
+----+--------------------+
| id | schema_name |
+----+--------------------+
| 1 | information_schema |
| 2 | mysql |
| 3 | performance_schema |
| 4 | test |
| 8 | eight |
| 9 | nine |
| 20 | foo |
| 21 | bar |
| 30 | bletch |
| 31 | baz |
+----+--------------------+
10 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Final state of schema_names table. AUTO_INCREMENT value shows the next inserted row would get ID=32.
*************************** 1. row *************************** Table: schema_names
Create Table: CREATE TABLE `schema_names` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL, PRIMARY KEY (`id`), KEY `i_schema` (`schema_name`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

例 14.7 LOCK 句を使用した並列性の制御

この例は、ALTER TABLE ステートメントの LOCK 句を使用して、オンライン DDL 操作の進行中にテーブルへの並列アクセスを許可または拒否する方法を示しています。この句には、クエリーと DML ステートメントを許可するか (LOCK=NONE)、クエリーのみを許可するか (LOCK=SHARED)、または並列アクセスをまったく許可しない (LOCK=EXCLUSIVE) 設定があります。

ここでは、いずれかのセッションの待機中またはデッドロック中の動作を確認するために、LOCK 句の異なる値を使用して、1 つのセッションで連続した ALTER TABLE ステートメントを実行してインデックスを作成および削除します。前の例と同じ BIG_TABLE テーブルを使用し、約 170 万行から始めます。説明のために、IS_NULLABLE カラムに対してインデックス作成とクエリーを実行します。(ただし、実際には、固有の値が 2 つしかない非常に小さなカラムのインデックスを作成することはありえません。)

mysql: desc big_table;
+--------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+---------------------+------+-----+---------+----------------+
| TABLE_CATALOG | varchar(512) | NO | | | |
| TABLE_SCHEMA | varchar(64) | NO | | | |
| TABLE_NAME | varchar(64) | NO | | | |
| COLUMN_NAME | varchar(64) | NO | | | |
| ORDINAL_POSITION | bigint(21) unsigned | NO | | 0 | |
| COLUMN_DEFAULT | longtext | YES | | NULL | || IS_NULLABLE | varchar(3) | NO | | | |...
+--------------------------+---------------------+------+-----+---------+----------------+
21 rows in set (0.14 sec)
mysql: alter table big_table add index i1(is_nullable);
Query OK, 0 rows affected (20.71 sec)
mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.02 sec)
mysql: alter table big_table add index i1(is_nullable), lock=exclusive;
Query OK, 0 rows affected (19.44 sec)
mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.03 sec)
mysql: alter table big_table add index i1(is_nullable), lock=shared;
Query OK, 0 rows affected (16.71 sec)
mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.05 sec)
mysql: alter table big_table add index i1(is_nullable), lock=none;
Query OK, 0 rows affected (12.26 sec)
mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.01 sec)
... repeat statements like the above while running queries ...
... and DML statements at the same time in another session ...

DDL ステートメントを実行しているセッションでは、特別なことは何も発生しません。場合によっては、別のトランザクションが DDL 中にテーブルを変更したか、または DDL の前にテーブルをクエリーしたとき、そのトランザクションの完了を待機しているために ALTER TABLE に非常に長い時間がかかることがあります。

mysql: alter table big_table add index i1(is_nullable), lock=none;Query OK, 0 rows affected (59.27 sec)mysql: -- The previous ALTER took so long because it was waiting for all the concurrent
mysql: -- transactions to commit or roll back.
mysql: alter table big_table drop index i1;Query OK, 0 rows affected (41.05 sec)mysql: -- Even doing a SELECT on the table in the other session first causes
mysql: -- the ALTER TABLE above to stall until the transaction
mysql: -- surrounding the SELECT is committed or rolled back.

同時に実行されている別のセッションのログを次に示します。ここでは、前のリストに示されている DDL 操作の前、最中、およびあとにテーブルに対してクエリーと DML ステートメントを発行しています。この最初のリストは、クエリーのみを示しています。LOCK=NONE または LOCK=SHARED を使用して DDL 操作中にクエリーが許可されること、および ALTER TABLE ステートメントに LOCK=EXCLUSIVE が含まれている場合は DDL が完了するまでクエリーが待機することを予測しています。

mysql: show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.01 sec)
mysql: -- A trial query before any ADD INDEX in the other session:
mysql: -- Note: because autocommit is enabled, each
mysql: -- transaction finishes immediately after the query.
mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO |
| YES |
+-------------+
2 rows in set (4.49 sec)
mysql: -- Index is being created with LOCK=EXCLUSIVE on the ALTER statement.
mysql: -- The query waits until the DDL is finished before proceeding.
mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO |
| YES |
+-------------+2 rows in set (17.26 sec)mysql: -- Index is being created with LOCK=SHARED on the ALTER statement.
mysql: -- The query returns its results while the DDL is in progress.
mysql: -- The same thing happens with LOCK=NONE on the ALTER statement.
mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO |
| YES |
+-------------+2 rows in set (3.11 sec)mysql: -- Once the index is created, and with no DDL in progress,
mysql: -- queries referencing the indexed column are very fast:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 411648 |
+----------+1 row in set (0.20 sec)mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO |
| YES |
+-------------+2 rows in set (0.00 sec)

次に、この並列セッションで、DML ステートメントまたは DML ステートメントとクエリーの組み合わせを含むいくつかのトランザクションを実行します。テーブルへの予測可能かつ検証可能な変更を示すために、DELETE ステートメントを使用します。この部分にあるトランザクションは複数のステートメントにまたがる場合があるため、これらのテストは autocommit がオフになった状態で実行します。

mysql: set global autocommit = off;
Query OK, 0 rows affected (0.00 sec)
mysql: -- Count the rows that will be involved in our DELETE statements:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 411648 |
+----------+
1 row in set (0.95 sec)
mysql: -- After this point, any DDL statements back in the other session
mysql: -- stall until we commit or roll back.
mysql: delete from big_table where is_nullable = 'YES' limit 11648;
Query OK, 11648 rows affected (0.14 sec)
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 400000 |
+----------+
1 row in set (1.04 sec)
mysql: rollback;
Query OK, 0 rows affected (0.09 sec)
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 411648 |
+----------+
1 row in set (0.93 sec)
mysql: -- OK, now we're going to try that during index creation with LOCK=NONE.
mysql: delete from big_table where is_nullable = 'YES' limit 11648;
Query OK, 11648 rows affected (0.21 sec)
mysql: -- We expect that now there will be 400000 'YES' rows left:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 400000 |
+----------+
1 row in set (1.25 sec)
mysql: -- In the other session, the ALTER TABLE is waiting before finishing,
mysql: -- because _this_ transaction hasn't committed or rolled back yet.
mysql: rollback;
Query OK, 0 rows affected (0.11 sec)
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 411648 |
+----------+
1 row in set (0.19 sec)
mysql: -- The ROLLBACK left the table in the same state we originally found it.
mysql: -- Now let's make a permanent change while the index is being created,
mysql: -- again with ALTER TABLE ... , LOCK=NONE.
mysql: -- First, commit so the DROP INDEX in the other shell can finish;
mysql: -- the previous SELECT started a transaction that accessed the table.
mysql: commit;
Query OK, 0 rows affected (0.00 sec)
mysql: -- Now we add the index back in the other shell, then issue DML in this one
mysql: -- while the DDL is running.
mysql: delete from big_table where is_nullable = 'YES' limit 11648;
Query OK, 11648 rows affected (0.23 sec)
mysql: commit;
Query OK, 0 rows affected (0.01 sec)
mysql: -- In the other shell, the ADD INDEX has finished.
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 400000 |
+----------+
1 row in set (0.19 sec)
mysql: -- At the point the new index is finished being created, it contains entries
mysql: -- only for the 400000 'YES' rows left when all concurrent transactions are finished.
mysql:
mysql: -- Now we will run a similar test, while ALTER TABLE ... , LOCK=SHARED is running.
mysql: -- We expect a query to complete during the ALTER TABLE, but for the DELETE
mysql: -- to run into some kind of issue.
mysql: commit;
Query OK, 0 rows affected (0.00 sec)
mysql: -- As expected, the query returns results while the LOCK=SHARED DDL is running:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 400000 |
+----------+
1 row in set (2.07 sec)
mysql: -- The DDL in the other session is not going to finish until this transaction
mysql: -- is committed or rolled back. If we tried a DELETE now and it waited because
mysql: -- of LOCK=SHARED on the DDL, both transactions would wait forever (deadlock).
mysql: -- MySQL detects this condition and cancels the attempted DML statement.
mysql: delete from big_table where is_nullable = 'YES' limit 100000;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
mysql: -- The transaction here is still going, so in the other shell, the ADD INDEX operation
mysql: -- is waiting for this transaction to commit or roll back.
mysql: rollback;
Query OK, 0 rows affected (0.00 sec)
mysql: -- Now let's try issuing a query and some DML, on one line, while running
mysql: -- ALTER TABLE ... , LOCK=EXCLUSIVE in the other shell.
mysql: -- Notice how even the query is held up until the DDL is finished.
mysql: -- By the time the DELETE is issued, there is no conflicting access
mysql: -- to the table and we avoid the deadlock error.
mysql: select count(*) from big_table where is_nullable = 'YES'; delete from big_table where is_nullable = 'YES' limit 100000;
+----------+
| count(*) |
+----------+
| 400000 |
+----------+1 row in set (15.98 sec)Query OK, 100000 rows affected (2.81 sec)
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 300000 |
+----------+
1 row in set (0.17 sec)
mysql: rollback;
Query OK, 0 rows affected (1.36 sec)
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 400000 |
+----------+
1 row in set (0.19 sec)
mysql: commit;
Query OK, 0 rows affected (0.00 sec)
mysql: -- Next, we try ALTER TABLE ... , LOCK=EXCLUSIVE in the other session
mysql: -- and only issue DML, not any query, in the concurrent transaction here.
mysql: delete from big_table where is_nullable = 'YES' limit 100000;Query OK, 100000 rows affected (16.37 sec)mysql: -- That was OK because the ALTER TABLE did not have to wait for the transaction
mysql: -- here to complete. The DELETE in this session waited until the index was ready.
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
| 300000 |
+----------+
1 row in set (0.16 sec)
mysql: commit;
Query OK, 0 rows affected (0.00 sec)

前のリスト例では、次のことがわかりました。

  • ALTER TABLELOCK 句は、ステートメントの残りの部分からカンマで区切られます。

  • オンライン DDL 操作は、テーブルにアクセスする以前のいずれかのトランザクションがコミットまたはロールバックされるまで、開始前に待機する可能性があります。

  • オンライン DDL 操作は、テーブルにアクセスするいずれかの並列トランザクションがコミットまたはロールバックされるまで、完了前に待機する可能性があります。

  • ALTER TABLE ステートメントが LOCK=NONE または LOCK=SHARED を使用しているかぎり、オンライン DDL 操作が実行されている間の並列クエリーの動作は比較的単純です。

  • autocommit がオンとオフのどちらになっているかに注意を払ってください。オフになっている場合は、テーブルで DDL 操作を実行する前にほかのセッションのトランザクション (クエリーだけであっても) を終了するときは注意してください。

  • LOCK=SHARED では、クエリーと DML が混在した並列トランザクションでデッドロックエラーが発生する可能性があるため、DDL が完了したあとにこれらのトランザクションを再開する必要があります。

  • LOCK=NONE では、並列トランザクションにクエリーと DML を自由に混在させることができます。DDL 操作は、並列トランザクションがコミットまたはロールバックされるまで待機します。

  • LOCK=EXCLUSIVE では、並列トランザクションにクエリーと DML を自由に混在させることができますが、これらのトランザクションは、DDL 操作が完了するまで待機したあとでしかテーブルにアクセスできません。


例 14.8 オンライン DDL 実験のためのスキーマ設定コード

1 つの ALTER TABLE ステートメントでテーブル上に複数のインデックスを作成できます。テーブルのクラスタ化されたインデックスは 1 回しかスキャンする必要がない (ただし、データは新しいインデックスごとに個別にソートされます) ため、これはかなり効率的です。例:

CREATE TABLE T1(A INT PRIMARY KEY, B INT, C CHAR(1)) ENGINE=InnoDB;
INSERT INTO T1 VALUES (1,2,'a'), (2,3,'b'), (3,2,'c'), (4,3,'d'), (5,2,'e');
COMMIT;
ALTER TABLE T1 ADD INDEX (B), ADD UNIQUE INDEX (C);

カラム A に主キーを持つ上のステートメント CREATE TABLE T1 は、いくつかの行を挿入したあと、カラム BC に 2 つの新しいインデックスを構築します。ALTER TABLE ステートメントの前に T1 に多数の行が挿入されていたとすると、このアプローチは、データをロードする前にすべてのセカンダリインデックスを作成するよりはるかに効率的です。

InnoDB セカンダリインデックスの削除にもテーブルデータのコピーは必要ないため、1 つの ALTER TABLE ステートメントまたは複数の DROP INDEX ステートメントで複数のインデックスを削除することは等しく効率的です。

ALTER TABLE T1 DROP INDEX B, DROP INDEX C;

または

DROP INDEX B ON T1;
DROP INDEX C ON T1;

例 14.9 主キーの作成および削除

InnoDB テーブルのクラスタ化されたインデックスの再構成には常に、テーブルデータのコピーが必要です。そのため、テーブルの再構築を回避するために、あとで ALTER TABLE ... ADD PRIMARY KEY を発行するのではなく、テーブルの作成時に主キーを定義することをお勧めします。

次の例のように、あとで PRIMARY KEY を定義した場合はデータがコピーされます。

CREATE TABLE T2 (A INT, B INT);
INSERT INTO T2 VALUES (NULL, 1);
ALTER TABLE T2 ADD PRIMARY KEY (B);

UNIQUE または PRIMARY KEY インデックスを作成したとき、MySQL は、いくつかの追加の作業を行う必要があります。UNIQUE インデックスの場合、MySQL は、テーブルに重複したキーの値が含まれていないことをチェックします。PRIMARY KEY インデックスの場合も、MySQL は、どの PRIMARY KEY カラムにも NULL が含まれていないことをチェックします。

ALGORITHM=COPY 句を使用して主キーを追加したとき、MySQL は実際には、関連付けられたカラム内の NULL 値をデフォルト値、つまり、数値の場合は 0、文字ベースのカラムや BLOB の場合は空の文字列、および DATETIME の場合は 0000-00-00 00:00:00 に変換します。これは非標準の動作であるため、これに依存しないようにすることをお勧めします。ALGORITHM=INPLACE を使用した主キーの追加は、SQL_MODE 設定に strict_trans_tables または strict_all_tables フラグが含まれている場合にのみ許可されます。SQL_MODE 設定が厳密である場合は、ADD PRIMARY KEY ... , ALGORITHM=INPLACE が許可されますが、要求された主キーカラムに NULL 値が含まれているとステートメントは引き続き失敗します。ALGORITHM=INPLACE の動作は、より標準に準拠しています。

次の例は、ADD PRIMARY KEY 句のいくつかの可能性を示しています。ALGORITHM=COPY 句を使用した場合、主キーカラム内に NULL 値が存在していても操作は成功します。データは暗黙のうちに変更され、それによって問題が発生する可能性があります。

mysql> CREATE TABLE add_pk_via_copy (c1 INT, c2 VARCHAR(10), c3 DATETIME);
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO add_pk_via_copy VALUES (1,'a','2014-11-03 11:01:37'),(NULL,NULL,NULL);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE add_pk_via_copy ADD PRIMARY KEY (c1,c2,c3), ALGORITHM=COPY;
Query OK, 2 rows affected, 3 warnings (0.07 sec)
Records: 2 Duplicates: 0 Warnings: 3
mysql> SHOW WARNINGS;
+---------+------+-----------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------+
| Warning | 1265 | Data truncated for column 'c1' at row 2 |
| Warning | 1265 | Data truncated for column 'c2' at row 2 |
| Warning | 1265 | Data truncated for column 'c3' at row 2 |
+---------+------+-----------------------------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM add_pk_via_copy;
+----+----+---------------------+
| c1 | c2 | c3 |
+----+----+---------------------+
| 0 | | 0000-00-00 00:00:00 |
| 1 | a | 2014-11-03 11:01:37 |
+----+----+---------------------+
2 rows in set (0.00 sec) 

ALGORITHM=INPLACE 句を使用した場合、この設定ではデータの整合性を高い優先度とみなしているため、操作はさまざまな理由で失敗する可能性があります。このステートメントは、SQL_MODE 設定が十分に厳密でない場合、または主キーカラムに NULL 値が含まれている場合にエラーを出力します。これらの両方の要件に対応すれば、ALTER TABLE 操作は成功します。

mysql> CREATE TABLE add_pk_via_inplace (c1 INT, c2 VARCHAR(10), c3 DATETIME);
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO add_pk_via_inplace VALUES (1,'a','2014-11-03 11:01:37'),(NULL,NULL,NULL);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM add_pk_via_inplace;
+------+------+---------------------+
| c1 | c2 | c3 |
+------+------+---------------------+
| 1 | a | 2014-11-03 11:01:37 |
| NULL | NULL | NULL |
+------+------+---------------------+
2 rows in set (0.00 sec)
mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE add_pk_via_inplace ADD PRIMARY KEY (c1,c2,c3), ALGORITHM=INPLACE;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: cannot silently convert NULL values,
as required in this SQL_MODE. Try ALGORITHM=COPY.
mysql> SET sql_mode ='strict_trans_tables';
Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE add_pk_via_inplace ADD PRIMARY KEY (c1,c2,c3), ALGORITHM=INPLACE;
ERROR 1138 (22004): Invalid use of NULL value
mysql> DELETE FROM add_pk_via_inplace WHERE c1 IS NULL OR c2 IS NULL OR c3 IS NULL;
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM add_pk_via_inplace;
+------+------+---------------------+
| c1 | c2 | c3 |
+------+------+---------------------+
| 1 | a | 2014-11-03 11:01:37 |
+------+------+---------------------+
1 row in set (0.00 sec)
mysql> ALTER TABLE add_pk_via_inplace ADD PRIMARY KEY (c1,c2,c3), ALGORITHM=INPLACE;
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0

主キーなしでテーブルを作成すると、InnoDB は、主キーを自動的に選択します。これは、NOT NULL カラムで定義された最初の UNIQUE キー、またはシステムで生成されたキーである場合があります。隠れた余分なカラムの不確実性や、それに対して領域要件が発生する可能性を排除するには、CREATE TABLE ステートメントの一部として PRIMARY KEY 句を指定します。


14.11.6 オンライン DDL の実装の詳細

InnoDB テーブルに対する各 ALTER TABLE 操作は、次のいくつかの側面によって制御されます。

  • テーブルの物理表現への何らかの変更があるかどうか、またはそれが純粋に、テーブル自体を変更することなく実行できるメタデータへの変更であるかどうか。

  • テーブル内のデータの量が同じままか、増えているか、または減っているか。

  • テーブルデータ内の変更がクラスタ化されたインデックス、セカンダリインデックス、またはその両方に関連しているかどうか。

  • 変更されるテーブルとその他のテーブルの間に何らかの外部キー関係が存在するかどうか。このメカニクスは、foreign_key_checks 構成オプションが有効または無効のどちらになっているかによって異なります。

  • テーブルがパーティション化されているかどうか。ALTER TABLE のパーティション化句は 1 つ以上のテーブルに関連する低レベルの操作に変換され、これらの操作はオンライン DDL の通常のルールに従います。

  • テーブルデータをコピーする必要があるかどうか、テーブルをインプレースで再編成できるかどうか、またはその両方の組み合わせか。

  • テーブルに自動インクリメントカラムが含まれているかどうか。

  • ベースとなるデータベース操作の性質、または ALTER TABLE ステートメントで指定した LOCK 句によって、どのようなレベルのロックが必要とされるか。

このセクションでは、これらの要因が InnoDB テーブルでのさまざまな種類の ALTER TABLE 操作にどのような影響を与えるかについて説明します。

オンライン DDL のエラー状態

オンライン DDL 操作が失敗する可能性がある主な理由を次に示します。

  • LOCK 句が、特定のタイプの DDL 操作とは互換性のない低レベルのロック (SHARED または NONE) を指定している場合。

  • DDL 操作の初期および最終フェーズ中に短時間だけ必要な、テーブルに対する排他的ロックの取得を待機している間にタイムアウトが発生した場合。

  • インデックス作成中に MySQL がディスク上に一時的なソートファイルを書き込んでいる間に tmpdir ファイルシステムのディスク領域が不足した場合。

  • ALTER TABLE に長い時間がかかりすぎたり、並列 DML によるテーブル変更が多すぎたりして、一時的なオンラインログのサイズが innodb_online_alter_log_max_size 構成オプションの値を超えた場合。この状態は DB_ONLINE_LOG_TOO_BIG エラーの原因になります。

  • 並列 DML が、元のテーブル定義では許可されるが、新しいテーブル定義では許可されないテーブルに変更を加えた場合。この操作は、MySQL がいちばん最後に、並列 DML ステートメントからのすべての変更を適用しようとしたときにのみ失敗します。たとえば、一意のインデックスの作成中にカラムに重複した値を挿入したり、そのカラムでの主キーのインデックスの作成中にカラムに NULL 値を挿入したりすることがあります。並列 DML によって行われた変更が優先され、ALTER TABLE 操作は実質的にロールバックされます。

構成オプション innodb_file_per_tableInnoDB テーブルの表現に大きな影響を与えますが、そのオプションが有効または無効のどちらになっているかや、テーブルが物理的に独自の .ibd ファイル内またはシステムテーブルスペースの内部のどちらに配置されているかにかかわらず、すべてのオンライン DDL 操作が同様に適切に機能します。

InnoDB には、テーブル内のすべてのデータを表すクラスタ化されたインデックスと、クエリーを高速化するためのオプションのセカンダリインデックスという 2 つのタイプのインデックスがあります。クラスタ化されたインデックスにはその B ツリーノード内のデータ値が含まれているため、クラスタ化されたインデックスの追加または削除には、データのコピーおよびテーブルの新しいコピーの作成が含まれます。ただし、セカンダリインデックスには、インデックスキーと主キーの値のみが含まれます。このタイプのインデックスは、クラスタ化されたインデックス内のデータをコピーすることなく作成または削除できます。各セカンダリインデックスには主キー値のコピー (必要に応じて、クラスタ化されたインデックスにアクセスするために使用されます) が含まれているため、主キーの定義を変更すると、すべてのセカンダリインデックスも再作成されます。

セカンダリインデックスの削除は単純です。内部の InnoDB システムテーブルと MySQL データディクショナリテーブルが、このインデックスは存在しなくなったという事実を反映するように更新されるだけです。InnoDB は、このインデックスに使用されているストレージをそれが含まれていたテーブルスペースに返して、新しいインデックスまたは追加のテーブル行がこの領域を使用できるようにします。

既存のテーブルにセカンダリインデックスを追加するには、InnoDB はそのテーブルをスキャンし、メモリーバッファーや一時ファイルを使用して各行をセカンダリインデックスキーカラムの値で順番にソートします。次に、B ツリーがキー値の順序で構築されます。これは、行をインデックスにランダムな順序で挿入するより効率的です。B ツリーノードはいっぱいになると分割されるため、このようにしてインデックスを構築するとインデックスのフィルファクタが高くなり、以降のアクセスがより効率的になります。

主キーと副キーのインデックス

従来より、MySQL サーバーと InnoDB はそれぞれ、テーブルおよびインデックス構造に関する独自のメタデータを保持しています。MySQL サーバーがこれらの情報を、トランザクションメカニズムによって保護されない .frm ファイル内に格納するのに対して、InnoDB は、独自のデータディクショナリシステムテーブルスペースの一部として保持しています。DDL 操作が途中でクラッシュまたはその他の予期しないイベントによって中断された場合は、メタデータがこれらの 2 つの場所の間で整合性がない状態のままになり、起動エラーや、変更の途中であったテーブルへのアクセス不可などの問題が発生する可能性があります。InnoDB は現在、デフォルトのストレージエンジンであるため、このような問題への対処は高い優先度を持っています。これらの DDL 操作への拡張により、このような問題が発生する可能性のある期間が削減されます。

14.11.7 オンライン DDL でのクラッシュリカバリの動作のしくみ

ALTER TABLE ステートメントの実行中にサーバーがクラッシュしてもデータは失われませんが、クラッシュリカバリのプロセスは、クラスタ化されたインデックスの場合とセカンダリインデックスの場合で異なります。

InnoDB セカンダリインデックスの作成中にサーバーがクラッシュした場合、MySQL はリカバリ時に、部分的に作成されたインデックスをすべて削除します。ALTER TABLE または CREATE INDEX ステートメントを再実行する必要があります。

InnoDB のクラスタ化されたインデックスの作成中にクラッシュが発生した場合は、テーブル内のデータをまったく新しいクラスタ化されたインデックスにコピーする必要があるため、リカバリはより複雑です。すべての InnoDB テーブルが、クラスタ化されたインデックスとして格納されることに注意してください。次の説明では、テーブルとクラスタ化されたインデックスという言葉を区別なく使用しています。

MySQL は、既存のデータを元の InnoDB テーブルから目的のインデックス構造を持つ一時テーブルにコピーすることによって、新しいクラスタ化されたインデックスを作成します。データがこの一時テーブルに完全にコピーされたら、元のテーブルの名前が別の一時テーブル名に変更されます。新しいクラスタ化されたインデックスで構成される一時テーブルの名前が元のテーブルの名前に変更され、元のテーブルはデータベースから削除されます。

新しいクラスタ化されたインデックスの作成中にシステムクラッシュが発生した場合、データは失われませんが、このプロセス中に存在する一時テーブルを使用してリカバリプロセスを完了する必要があります。クラスタ化されたインデックスを再作成したり、大きなテーブルで主キーを再定義したり、あるいはこの操作中にシステムクラッシュが発生したりすることはまれであるため、このマニュアルではこのシナリオからのリカバリに関する情報は提供していません。

14.11.8 パーティション化された InnoDB テーブルに対するオンライン DDL

ALTER TABLE のパーティション化句を除き、パーティション化された InnoDB テーブルに対するオンライン DDL 操作は、通常の InnoDB テーブルに適用されるのと同じルールに従います。オンライン DDL のルールは、表14.5「DDL 操作のオンラインステータスのサマリー」で概説されています。

ALTER TABLE のパーティション化句は、通常のパーティション化されていない InnoDB テーブルと同じ内部のオンライン DDL API を経由せず、ALGORITHM=DEFAULT および LOCK=DEFAULT との組み合わせでのみ許可されます。

ALTER TABLE ステートメントで ALTER TABLE のパーティション化句を使用した場合、パーティション化されたテーブルは、ALTER TABLECOPY アルゴリズムを使用して再パーティション化されます。つまり、新しいパーティション化されたテーブルは、新しいパーティション化スキームで作成されます。新しく作成されたテーブルには ALTER TABLE ステートメントによって適用されたすべての変更が含まれ、テーブルデータが新しいテーブル構造にコピーされます。

ALTER TABLE のパーティション化句を使用してテーブルのパーティション化を変更しない場合、または ALTER TABLE ステートメントでほかの何らかのパーティション管理を実行した場合、ALTER TABLE は、各テーブルパーティションで INPLACE アルゴリズムを使用します。ただし、INPLACEALTER TABLE 操作が各パーティションで実行されると、複数のパーティションで実行されている操作のために、システムリソースへの要求が増加することに注意してください。

ALTER TABLE ステートメントのパーティション化句が、通常のパーティション化されていない InnoDB テーブルと同じ内部のオンライン DDL API を経由しないにもかかわらず、MySQL は引き続き、可能な場合はデータコピーとロックを最小限に抑えようとします。

  • RANGE または LIST によってパーティション化されたテーブルに対する ADD PARTITION および DROP PARTITION では、どの既存のデータもコピーされません。

  • TRUNCATE PARTITION では、すべてのタイプのパーティション化されたテーブルについて、どの既存のデータもコピーされません。

  • 並列クエリーは、HASH または LIST によってパーティション化されたテーブルに対する ADD PARTITION および COALESCE PARTITION 中に許可されます。MySQL は、共有ロックを保持している間にデータをコピーします。

  • REORGANIZE PARTITIONREBUILD PARTITION、あるいは LINEAR HASH または LIST によってパーティション化されたテーブルに対する ADD PARTITION または COALESCE PARTITION では、並列クエリーが許可されます。影響を受けるパーティションからのデータは、テーブルレベルの共有メタデータ (読み取り) ロックを保持している間にコピーされます。

注記

InnoDB のパーティション化されたテーブルでは、全文検索 (FTS) と外部キーはサポートされていません。詳細は、セクション12.9.5「全文制限」およびセクション19.6.2「ストレージエンジンに関連するパーティショニング制限」を参照してください。

14.11.9 オンライン DDL の制限

オンライン DDL 操作を実行する場合は、次の制限を考慮に入れてください。

  • テーブルをコピーするオンライン DDL 操作中に、ファイルは一時ディレクトリ (Unix では $TMPDIR、Windows では %TEMP%、または --tmpdir 構成変数で指定されたディレクトリ) に書き込まれます。各一時ファイルは、新しいテーブルまたはインデックス内に 1 つのカラムを保持できるだけの十分な大きさを持ち、最終的なテーブルまたはインデックスにマージされたらすぐに削除されます。

  • どちらも同じインデックスを指定する DROP INDEX および ADD INDEX 句を含む ALTER TABLE ステートメントは、高速インデックス作成ではなくテーブルコピーを使用します。

  • TEMPORARY TABLE でインデックスを作成した場合は、高速インデックス作成が使用されるのではなく、テーブルがコピーされます。これは MySQL Bug #39833 としてレポートされています。

  • InnoDB は、外部キーに必要なインデックスをユーザーが削除しようとしたときにエラー事例を処理します。エラー 1553 に関連した詳細は、セクション14.19.5「InnoDB のエラーコード」を参照してください。

  • ALTER TABLE の句 LOCK=NONE は、テーブル上に ON...CASCADE または ON...SET NULL 制約が存在する場合は許可されません。

  • オンライン DDL の各 ALTER TABLE ステートメント中に、LOCK 句には関係なく、テーブルに対する排他的ロック (LOCK=EXCLUSIVE 句で指定されるのと同じ種類のロック) を必要とする短い期間が最初と最後に存在します。そのため、そのテーブル上で挿入、更新、削除、または SELECT ... FOR UPDATE を実行している長時間実行されるトランザクションが存在する場合は、オンライン DDL 操作が開始前に待機する可能性があります。また、ALTER TABLE の進行中に同様の長時間実行されるトランザクションが開始された場合は、オンライン DDL 操作が完了前に待機する可能性があります。

  • オンライン ALTER TABLE 操作の実行時に、ALTER TABLE 操作を実行しているスレッドは、その同じテーブルに対してほかの接続スレッドから同時に実行された DML 操作のオンラインログを適用します。これらの DML 操作が適用されると、重複したキーエントリのエラー (ERROR 1062 (23000): 重複したエントリ) が発生する可能性があります。これは、重複したエントリが一時的なだけで、オンラインログのあとの方のエントリによって元に戻されるとしても同じです。これは、トランザクション中は制約を保持する必要のある、InnoDB での外部キー制約チェックの考え方に似ています。

  • InnoDB テーブルに対する OPTIMIZE TABLE は、テーブルを再構築して、インデックス統計を更新し、クラスタ化されたインデックス内の未使用領域を解放するための ALTER TABLE 操作にマップされます。5.6.17 より前は、この操作に対するオンライン DDL のサポートはありません。主キーに現れる順序でキーが挿入されるため、セカンダリインデックスはそれほど効率的に作成されません。5.6.17 の時点では、InnoDB の通常のテーブルとパーティション化されたテーブルを再構築するためのオンライン DDL のサポートの追加によって、OPTIMIZE TABLE がサポートされます。詳細は、セクション14.11.1「オンライン DDL の概要」を参照してください。

  • MySQL 5.6 より前に作成された InnoDB テーブルは、一時的なカラム (DATEDATETIME、または TIMESTAMP) を含み、かつ ALTER TABLE ... ALGORITHM=COPY を使用して再構築されていないテーブルに対する ALTER TABLE ... ALGORITHM=INPLACE をサポートしていません。この場合は、ALTER TABLE ... ALGORITHM=INPLACE 操作によって次のエラーが返されます。

    ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
    Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

14.12 InnoDB の起動オプションおよびシステム変数

  • true または false であるシステム変数は、サーバー起動時に変数の名前を指定することで有効にすることができ、--skip- プリフィクスを使用することで無効にすることができます。たとえば、InnoDB 適応型ハッシュインデックスを有効または無効にするには、コマンド行で --innodb_adaptive_hash_index または --skip-innodb_adaptive_hash_index を使用するか、オプションファイルで innodb_adaptive_hash_index または skip-innodb_adaptive_hash_index を使用します。

  • 数値が指定されるシステム変数は、コマンド行で --var_name=value として指定するか、オプションファイルで var_name=value として指定できます。

  • 多くのシステム変数は、実行時に変更できます (セクション5.1.5.2「動的システム変数」を参照してください)。

  • GLOBAL および SESSION 変数スコープ修飾子については、SET ステートメントのドキュメントを参照してください。

  • 特定のオプションでは、InnoDB データファイルの場所およびレイアウトが制御されます。セクション14.3「InnoDB の構成」では、これらのオプションを使用する方法について説明します。

  • 初期段階では使用しないような一部のオプションは、マシンの処理能力やデータベースのワークロードに基づいて、InnoDB のパフォーマンス特性を調整する際に役立ちます。

  • オプションおよびシステム変数の指定に関する詳細は、セクション4.2.3「プログラムオプションの指定」を参照してください。

表 14.6 InnoDB オプション/変数のリファレンス

名前コマンド行オプションファイルシステム変数ステータス変数変数スコープ動的
daemon_memcached_enable_binlogはいはいはいグローバルいいえ
daemon_memcached_engine_lib_nameはいはいはいグローバルいいえ
daemon_memcached_engine_lib_pathはいはいはいグローバルいいえ
daemon_memcached_optionはいはいはいグローバルいいえ
daemon_memcached_r_batch_sizeはいはいはいグローバルいいえ
daemon_memcached_w_batch_sizeはいはいはいグローバルいいえ
foreign_key_checksはい両方はい
have_innodbはいグローバルいいえ
ignore_builtin_innodbはいはいはいグローバルいいえ
innodbはいはい
innodb_adaptive_flushingはいはいはいグローバルはい
innodb_adaptive_flushing_lwmはいはいはいグローバルはい
innodb_adaptive_hash_indexはいはいはいグローバルはい
innodb_adaptive_max_sleep_delayはいはいはいグローバルはい
innodb_additional_mem_pool_sizeはいはいはいグローバルいいえ
innodb_api_bk_commit_intervalはいはいはいグローバルはい
innodb_api_disable_rowlockはいはいはいグローバルいいえ
innodb_api_enable_binlogはいはいはいグローバルいいえ
innodb_api_enable_mdlはいはいはいグローバルいいえ
innodb_api_trx_levelはいはいはいグローバルはい
innodb_autoextend_incrementはいはいはいグローバルはい
innodb_autoinc_lock_modeはいはいはいグローバルいいえ
Innodb_available_undo_logsはいグローバルいいえ
Innodb_buffer_pool_bytes_dataはいグローバルいいえ
Innodb_buffer_pool_bytes_dirtyはいグローバルいいえ
innodb_buffer_pool_dump_at_shutdownはいはいはいグローバルはい
innodb_buffer_pool_dump_nowはいはいはいグローバルはい
Innodb_buffer_pool_dump_statusはいグローバルいいえ
innodb_buffer_pool_filenameはいはいはいグローバルはい
innodb_buffer_pool_instancesはいはいはいグローバルいいえ
innodb_buffer_pool_load_abortはいはいはいグローバルはい
innodb_buffer_pool_load_at_startupはいはいはいグローバルいいえ
innodb_buffer_pool_load_nowはいはいはいグローバルはい
Innodb_buffer_pool_load_statusはいグローバルいいえ
Innodb_buffer_pool_pages_dataはいグローバルいいえ
Innodb_buffer_pool_pages_dirtyはいグローバルいいえ
Innodb_buffer_pool_pages_flushedはいグローバルいいえ
Innodb_buffer_pool_pages_freeはいグローバルいいえ
Innodb_buffer_pool_pages_latchedはいグローバルいいえ
Innodb_buffer_pool_pages_miscはいグローバルいいえ
Innodb_buffer_pool_pages_totalはいグローバルいいえ
Innodb_buffer_pool_read_aheadはいグローバルいいえ
Innodb_buffer_pool_read_ahead_evictedはいグローバルいいえ
Innodb_buffer_pool_read_requestsはいグローバルいいえ
Innodb_buffer_pool_readsはいグローバルいいえ
innodb_buffer_pool_sizeはいはいはいグローバルいいえ
Innodb_buffer_pool_wait_freeはいグローバルいいえ
Innodb_buffer_pool_write_requestsはいグローバルいいえ
innodb_change_buffer_max_sizeはいはいはいグローバルはい
innodb_change_bufferingはいはいはいグローバルはい
innodb_checksum_algorithmはいはいはいグローバルはい
innodb_checksumsはいはいはいグローバルいいえ
innodb_cmp_per_index_enabledはいはいはいグローバルはい
innodb_commit_concurrencyはいはいはいグローバルはい
innodb_compression_failure_threshold_pctはいはいはいグローバルはい
innodb_compression_levelはいはいはいグローバルはい
innodb_compression_pad_pct_maxはいはいはいグローバルはい
innodb_concurrency_ticketsはいはいはいグローバルはい
innodb_data_file_pathはいはいはいグローバルいいえ
Innodb_data_fsyncsはいグローバルいいえ
innodb_data_home_dirはいはいはいグローバルいいえ
Innodb_data_pending_fsyncsはいグローバルいいえ
Innodb_data_pending_readsはいグローバルいいえ
Innodb_data_pending_writesはいグローバルいいえ
Innodb_data_readはいグローバルいいえ
Innodb_data_readsはいグローバルいいえ
Innodb_data_writesはいグローバルいいえ
Innodb_data_writtenはいグローバルいいえ
Innodb_dblwr_pages_writtenはいグローバルいいえ
Innodb_dblwr_writesはいグローバルいいえ
innodb_disable_sort_file_cacheはいはいはいグローバルはい
innodb_doublewriteはいはいはいグローバルいいえ
innodb_fast_shutdownはいはいはいグローバルはい
innodb_file_formatはいはいはいグローバルはい
innodb_file_format_checkはいはいはいグローバルいいえ
innodb_file_format_maxはいはいはいグローバルはい
innodb_file_per_tableはいはいはいグローバルはい
innodb_flush_log_at_timeoutはいグローバルはい
innodb_flush_log_at_trx_commitはいはいはいグローバルはい
innodb_flush_methodはいはいはいグローバルいいえ
innodb_flush_neighborsはいはいはいグローバルはい
innodb_flushing_avg_loopsはいはいはいグローバルはい
innodb_force_load_corruptedはいはいはいグローバルいいえ
innodb_force_recoveryはいはいはいグローバルいいえ
innodb_ft_aux_tableはいグローバルはい
innodb_ft_cache_sizeはいはいはいグローバルいいえ
innodb_ft_enable_diag_printはいはいはいグローバルはい
innodb_ft_enable_stopwordはいはいはいグローバルはい
innodb_ft_max_token_sizeはいはいはいグローバルいいえ
innodb_ft_min_token_sizeはいはいはいグローバルいいえ
innodb_ft_num_word_optimizeはいはいはいグローバルはい
innodb_ft_result_cache_limitはいはいはいグローバルはい
innodb_ft_server_stopword_tableはいはいはいグローバルはい
innodb_ft_sort_pll_degreeはいはいはいグローバルいいえ
innodb_ft_total_cache_sizeはいはいはいグローバルいいえ
innodb_ft_user_stopword_tableはいはいはい両方はい
Innodb_have_atomic_builtinsはいグローバルいいえ
innodb_io_capacityはいはいはいグローバルはい
innodb_io_capacity_maxはいはいはいグローバルはい
innodb_large_prefixはいはいはいグローバルはい
innodb_lock_wait_timeoutはいはいはい両方はい
innodb_locks_unsafe_for_binlogはいはいはいグローバルいいえ
innodb_log_buffer_sizeはいはいはいグローバルいいえ
innodb_log_compressed_pagesはいはいはいグローバルはい
innodb_log_file_sizeはいはいはいグローバルいいえ
innodb_log_files_in_groupはいはいはいグローバルいいえ
innodb_log_group_home_dirはいはいはいグローバルいいえ
Innodb_log_waitsはいグローバルいいえ
Innodb_log_write_requestsはいグローバルいいえ
Innodb_log_writesはいグローバルいいえ
innodb_lru_scan_depthはいはいはいグローバルはい
innodb_max_dirty_pages_pctはいはいはいグローバルはい
innodb_max_dirty_pages_pct_lwmはいはいはいグローバルはい
innodb_max_purge_lagはいはいはいグローバルはい
innodb_max_purge_lag_delayはいはいはいグローバルはい
innodb_mirrored_log_groupsはいはいはいグローバルいいえ
innodb_monitor_disableはいはいはいグローバルはい
innodb_monitor_enableはいはいはいグローバルはい
innodb_monitor_resetはいはいはいグローバルはい
innodb_monitor_reset_allはいはいはいグローバルはい
Innodb_num_open_filesはいグローバルいいえ
innodb_old_blocks_pctはいはいはいグローバルはい
innodb_old_blocks_timeはいはいはいグローバルはい
innodb_online_alter_log_max_sizeはいはいはいグローバルはい
innodb_open_filesはいはいはいグローバルいいえ
innodb_optimize_fulltext_onlyはいはいはいグローバルはい
Innodb_os_log_fsyncsはいグローバルいいえ
Innodb_os_log_pending_fsyncsはいグローバルいいえ
Innodb_os_log_pending_writesはいグローバルいいえ
Innodb_os_log_writtenはいグローバルいいえ
Innodb_page_sizeはいグローバルいいえ
innodb_page_sizeはいはいはいグローバルいいえ
Innodb_pages_createdはいグローバルいいえ
Innodb_pages_readはいグローバルいいえ
Innodb_pages_writtenはいグローバルいいえ
innodb_print_all_deadlocksはいはいはいグローバルはい
innodb_purge_batch_sizeはいはいはいグローバルはい
innodb_purge_threadsはいはいはいグローバルいいえ
innodb_random_read_aheadはいはいはいグローバルはい
innodb_read_ahead_thresholdはいはいはいグローバルはい
innodb_read_io_threadsはいはいはいグローバルいいえ
innodb_read_onlyはいはいはいグローバルいいえ
innodb_replication_delayはいはいはいグローバルはい
innodb_rollback_on_timeoutはいはいはいグローバルいいえ
innodb_rollback_segmentsはいはいはいグローバルはい
Innodb_row_lock_current_waitsはいグローバルいいえ
Innodb_row_lock_timeはいグローバルいいえ
Innodb_row_lock_time_avgはいグローバルいいえ
Innodb_row_lock_time_maxはいグローバルいいえ
Innodb_row_lock_waitsはいグローバルいいえ
Innodb_rows_deletedはいグローバルいいえ
Innodb_rows_insertedはいグローバルいいえ
Innodb_rows_readはいグローバルいいえ
Innodb_rows_updatedはいグローバルいいえ
innodb_sort_buffer_sizeはいはいはいグローバルいいえ
innodb_spin_wait_delayはいはいはいグローバルはい
innodb_stats_auto_recalcはいはいはいグローバルはい
innodb_stats_methodはいはいはいグローバルはい
innodb_stats_on_metadataはいはいはいグローバルはい
innodb_stats_persistentはいはいはいグローバルはい
innodb_stats_persistent_sample_pagesはいはいはいグローバルはい
innodb_stats_sample_pagesはいはいはいグローバルはい
innodb_stats_transient_sample_pagesはいはいはいグローバルはい
innodb-status-fileはいはい
innodb_status_outputはいはいはいグローバルはい
innodb_status_output_locksはいはいはいグローバルはい
innodb_strict_modeはいはいはい両方はい
innodb_support_xaはいはいはい両方はい
innodb_sync_array_sizeはいはいはいグローバルいいえ
innodb_sync_spin_loopsはいはいはいグローバルはい
innodb_table_locksはいはいはい両方はい
innodb_thread_concurrencyはいはいはいグローバルはい
innodb_thread_sleep_delayはいはいはいグローバルはい
Innodb_truncated_status_writesはいグローバルいいえ
innodb_undo_directoryはいはいはいグローバルいいえ
innodb_undo_logsはいはいはいグローバルはい
innodb_undo_tablespacesはいはいはいグローバルいいえ
innodb_use_native_aioはいはいはいグローバルいいえ
innodb_use_sys_mallocはいはいはいグローバルいいえ
innodb_versionはいグローバルいいえ
innodb_write_io_threadsはいはいはいグローバルいいえ
timed_mutexesはいはいはいグローバルはい
unique_checksはい両方はい

InnoDB コマンドオプション

  • --ignore-builtin-innodb

    コマンド行形式--ignore-builtin-innodb
    非推奨はい
    システム変数ignore_builtin_innodb
    スコープグローバル
    動的いいえ
    ブール

    MySQL 5.1 では、このオプションを使用すると、サーバーは組み込み InnoDB が存在しない場合と同様に動作し、代わりに InnoDB Plugin を使用できました。MySQL 5.6 では、InnoDB がデフォルトのストレージエンジンとなり、InnoDB Plugin は使用されないため、このオプションは無効です。MySQL 5.6.5 の時点では、無視されます。

  • --innodb[=value]

    コマンド行形式--innodb[=value]
    非推奨5.6.21
    列挙
    デフォルトON
    有効な値

    OFF

    ON

    FORCE

    サーバーが InnoDB サポートでコンパイルされた場合に、InnoDB ストレージエンジンのロードを制御します。このオプションの形式はトライステートであり、指定可能な値は OFFON、または FORCE です。セクション5.1.8.1「プラグインのインストールおよびアンインストール」を参照してください。

    InnoDB を無効にするには、--innodb=OFF または --skip-innodb を使用します。この場合、デフォルトのストレージエンジンは InnoDB であるため、--default-storage-engine および --default-tmp-storage-engine を使用して、永続テーブルと TEMPORARY テーブルの両方についてデフォルトを別のエンジンに設定しないかぎりサーバーは開始しません。

    MySQL 5.6.21 の時点では、--innodb=OFF および --skip-innodb オプションが非推奨となり、使用すると警告が発生します。これらのオプションは、今後の MySQL リリースで削除されます。

  • --innodb-status-file

    コマンド行形式--innodb-status-file
    ブール
    デフォルトOFF

    InnoDB が MySQL データディレクトリに innodb_status.pid という名前のファイルを作成するかどうかを制御します。有効にすると、InnoDB は定期的に SHOW ENGINE INNODB STATUS の出力をこのファイルに書き込みます。

    このファイルはデフォルトでは作成されません。これを作成するには、--innodb-status-file=1 オプションを付けて mysqld を起動します。このファイルは、通常のシャットダウン中に削除されます。

  • --skip-innodb

    InnoDB ストレージエンジンを無効にします。--innodb の説明を参照してください。

InnoDB システム変数

  • daemon_memcached_enable_binlog

    コマンド行形式--daemon-memcached-enable-binlog=#
    導入5.6.6
    システム変数daemon_memcached_enable_binlog
    スコープグローバル
    動的いいえ
    ブール
    デフォルトfalse

    このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • daemon_memcached_engine_lib_name

    コマンド行形式--daemon-memcached-engine-lib-name=library
    導入5.6.6
    システム変数daemon_memcached_engine_lib_name
    スコープグローバル
    動的いいえ
    ファイル名
    デフォルトinnodb_engine.so

    InnoDBmemcached プラグインを実装する共有ライブラリを指定します。

    このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • daemon_memcached_engine_lib_path

    コマンド行形式--daemon-memcached-engine-lib-path=directory
    導入5.6.6
    システム変数daemon_memcached_engine_lib_path
    スコープグローバル
    動的いいえ
    ディレクトリ名
    デフォルトNULL

    InnoDBmemcached プラグインを実装する共有ライブラリを含むディレクトリのパスです。デフォルト値は、MySQL プラグインディレクトリを表す NULL です。MySQL プラグインディレクトリの外部に配置されている別のストレージエンジンの memcached プラグインを指定していなければ、このパラメータを変更する必要はないはずです。

    このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • daemon_memcached_option

    コマンド行形式--daemon-memcached-option=options
    導入5.6.6
    システム変数daemon_memcached_option
    スコープグローバル
    動的いいえ
    文字列
    デフォルト

    起動時に、空白文字で区切られた memcached オプションをベースとなる memcached メモリーオブジェクトのキャッシュデーモンに渡すために使用されます。たとえば、memcached が待機するポートを変更したり、同時接続の最大数を削減したり、鍵と値のペアの最大メモリーサイズを変更したり、エラーログに関するメッセージのデバッグを有効にしたりします。

    このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。memcached のオプションについては、memcached のマニュアルページを参照してください。

  • daemon_memcached_r_batch_size

    コマンド行形式--daemon-memcached-r-batch-size=#
    導入5.6.6
    システム変数daemon_memcached_r_batch_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト1

    COMMIT を実行して新しいトランザクションを開始する前に、実行される memcached 読み取り操作 (get) の数を指定します。daemon_memcached_w_batch_size の対の片方です。

    この値は、SQL ステートメントを使用してテーブルに行われた変更がすぐに memcached 操作に表示されるように、デフォルトで 1 に設定されています。ベースとなるテーブルが memcached インタフェースからのみアクセスされているシステム上で、頻繁なコミットによるオーバーヘッドを削減するために、これを大きくすることがあります。大きすぎる値を設定すると、Undo データまたは Redo データの量によっては、長時間実行されるトランザクションの場合と同様に、一部のストレージでオーバーヘッドが発生する可能性があります。

    このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • daemon_memcached_w_batch_size

    コマンド行形式--daemon-memcached-w-batch-size=#
    導入5.6.6
    システム変数daemon_memcached_w_batch_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト1

    COMMIT を実行して新しいトランザクションを開始する前に、実行される memcached 書き込み操作 (addsetincr など) の数を指定します。daemon_memcached_r_batch_size の対の一方です。

    この値は、格納されるデータはすべて停止に備えて保持しておくことが重要であり、すぐにコミットされるべきであるという仮定に基づいて、デフォルトで 1 に設定されています。クリティカルでないデータを格納するときは、頻繁なコミットによるオーバーヘッドを削減するために、この値を大きくすることがあります。ただし、クラッシュ時に、コミットされていない最後の N-1 回の書き込み操作が失われる可能性があります。

    このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • ignore_builtin_innodb

    コマンド行形式--ignore-builtin-innodb
    非推奨はい
    システム変数ignore_builtin_innodb
    スコープグローバル
    動的いいえ
    ブール

    このセクションの前半の InnoDB コマンドオプションの下にある --ignore-builtin-innodb の説明を参照してください。

  • innodb_adaptive_flushing

    コマンド行形式--innodb-adaptive-flushing=#
    システム変数innodb_adaptive_flushing
    スコープグローバル
    動的はい
    ブール
    デフォルトON

    ワークロードに基づいて、InnoDBバッファープール内のダーティーページをフラッシュする比率を動的に調整するかどうかを指定します。フラッシュ比率を動的に調整する目的は、I/O アクティビティーのバーストを回避することです。この設定はデフォルトで有効になっています。詳細は、セクション14.13.1.2「InnoDB バッファープールのフラッシュの頻度の構成」を参照してください。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_adaptive_flushing_lwm

    コマンド行形式--innodb-adaptive-flushing-lwm=#
    導入5.6.6
    システム変数innodb_adaptive_flushing_lwm
    スコープグローバル
    動的はい
    数値
    デフォルト10
    最小値0
    最大値70

    適応型フラッシュが有効になっている Redo ログ容量の割合を表す低位境界値です。

  • innodb_adaptive_hash_index

    コマンド行形式--innodb-adaptive-hash-index=#
    システム変数innodb_adaptive_hash_index
    スコープグローバル
    動的はい
    ブール
    デフォルトON

    InnoDB適応型ハッシュインデックスが有効と無効のどちらになっているのかを示します。ワークロードに応じて、適応型ハッシュインデックスの作成を動的に有効または無効にして、クエリーのパフォーマンスを改善することが望ましい場合があります。適応型ハッシュインデックスがすべてのワークロードに役立つとは限らないため、現実的なワークロードを使用して、有効と無効の両方でベンチマークを実施してください。詳細は、セクション14.2.13.6「適応型ハッシュインデックス」を参照してください。

    この変数はデフォルトで有効になっています。SET GLOBAL ステートメントを使用すると、サーバーを再起動せずに、このパラメータを変更できます。この設定を変更するには、SUPER 権限が必要です。また、サーバーの起動時に --skip-innodb_adaptive_hash_index を使用すると、無効にすることができます。

    適応型ハッシュインデックスを無効にすると、すぐにハッシュテーブルが空になります。ハッシュテーブルが空になっても通常の操作は続行でき、ハッシュテーブルを使用していた実行中のクエリーは、代わりにインデックスの B ツリーに直接アクセスします。適応型ハッシュインデックスを再度有効にすると、通常の操作時にハッシュテーブルが再度移入されます。

  • innodb_adaptive_max_sleep_delay

    コマンド行形式--innodb-adaptive-max-sleep-delay=#
    導入5.6.3
    システム変数innodb_adaptive_max_sleep_delay
    スコープグローバル
    動的はい
    数値
    デフォルト150000
    最小値0
    最大値1000000

    現在のワークロードに応じて、InnoDB によって自動的に innodb_thread_sleep_delay の値が上下に調整されるようにします。ゼロ以外の値に指定すると、最大で innodb_adaptive_max_sleep_delay オプションで指定された最大値まで、自動的に innodb_thread_sleep_delay 値の動的な調整が行われます。値はマイクロ秒数を表しています。このオプションは、InnoDB スレッド数が 16 個を上回る高負荷のシステムで役立つことがあります。(実際には、同時接続数が数百または数千になる MySQL システムの大部分の変数です。)

    詳細は、セクション14.13.5「InnoDB のスレッド並列性の構成」を参照してください。

  • innodb_additional_mem_pool_size

    コマンド行形式--innodb-additional-mem-pool-size=#
    非推奨5.6.3
    システム変数innodb_additional_mem_pool_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト8388608
    最小値2097152
    最大値4294967295

    データディクショナリ情報およびその他の内部データ構造を格納する際に InnoDB で使用されるメモリープールのサイズ (バイト単位) です。アプリケーションに存在するテーブル数が多いほど、ここで割り当てるメモリー量も多くなります。このプール内のメモリーが InnoDB によって使い果たされると、オペレーティングシステムからのメモリーの割り当てが開始され、MySQL エラーログに警告メッセージが書き込まれます。デフォルトの値は 8M バイトです。

    この変数は、InnoDB の内部メモリーアロケータに関連します。これは、innodb_use_sys_malloc が有効になっている場合は使用されません。MySQL 5.6.3 の時点では、innodb_additional_mem_pool_size は非推奨となり、今後の MySQL リリースで削除される予定です。

  • innodb_api_bk_commit_interval

    コマンド行形式--innodb-api-bk-commit-interval=#
    導入5.6.7
    システム変数innodb_api_bk_commit_interval
    スコープグローバル
    動的はい
    数値
    デフォルト5
    最小値1
    最大値1073741824

    InnoDBmemcached インタフェースが使用されるアイドル状態の接続が自動コミットされる頻度 (秒単位) です。このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • innodb_api_disable_rowlock

    コマンド行形式--innodb-api-disable-rowlock=#
    導入5.6.6
    システム変数innodb_api_disable_rowlock
    スコープグローバル
    動的いいえ
    ブール
    デフォルトOFF

    この変数を使用すると、InnoDBmemcached で DML 操作が実行されるときに、行ロックが無効になります。デフォルトでは、innodb_api_disable_rowlockOFF に設定されており、memcached が get および set 操作の行ロックをリクエストします。innodb_api_disable_rowlockON に設定すると、memcached は行ロックの代わりに、テーブルロックをリクエストします。

    innodb_api_disable_rowlock オプションは動的ではありません。これは mysqld コマンド行で指定するか、または MySQL 構成ファイルに入力する必要があります。構成は、MySQL サーバーが起動されるたびに行うプラグインのインストール時に有効になります。

  • innodb_api_enable_binlog

    コマンド行形式--innodb-api-enable-binlog=#
    導入5.6.6
    システム変数innodb_api_enable_binlog
    スコープグローバル
    動的いいえ
    ブール
    デフォルトOFF

    MySQL バイナリログとともに、InnoDBmemcached プラグインを使用できます。このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • innodb_api_enable_mdl

    コマンド行形式--innodb-api-enable-mdl=#
    導入5.6.6
    システム変数innodb_api_enable_mdl
    スコープグローバル
    動的いいえ
    ブール
    デフォルトOFF

    InnoDBmemcached プラグインで使用されるテーブルをロックします。これにより、SQL インタフェースから DDL によって削除または変更できなくなります。このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。

  • innodb_api_trx_level

    コマンド行形式--innodb-api-trx-level=#
    導入5.6.6
    システム変数innodb_api_trx_level
    スコープグローバル
    動的はい
    数値
    デフォルト0

    memcached インタフェースで処理されたクエリー上のトランザクション分離レベルを制御できます。このオプションの使用法の詳細は、セクション14.18「InnoDB と memcached の統合」を参照してください。よく聞く名前に対応する定数は、次のとおりです。

    • 0 = READ UNCOMMITTED

    • 1 = READ COMMITTED

    • 2 = REPEATABLE READ

    • 3 = SERIALIZABLE

  • innodb_autoextend_increment

    コマンド行形式--innodb-autoextend-increment=#
    システム変数innodb_autoextend_increment
    スコープグローバル
    動的はい
    数値
    デフォルト (≥ 5.6.6)64
    デフォルト (≤ 5.6.5)8
    最小値1
    最大値1000

    InnoDB の自動拡張システムテーブルスペースファイルがいっぱいになったときに、そのサイズを拡張する際の増分サイズ (M バイト単位) です。デフォルト値は、MySQL 5.6.6 の時点では 64、それよりも前では 8 です。この変数によって、innodb_file_per_table=1 を使用した場合に作成されるテーブルごとのテーブルスペースファイルは影響を受けません。innodb_autoextend_increment の値には関係なく、これらのファイルは自動拡張されます。拡張は少量で始まり、その後の拡張は増分が 4MB で発生します。

  • innodb_autoinc_lock_mode

    コマンド行形式--innodb-autoinc-lock-mode=#
    システム変数innodb_autoinc_lock_mode
    スコープグローバル
    動的いいえ
    数値
    デフォルト1
    有効な値

    0

    1

    2

    自動インクリメント値を生成する際に使用されるロックモードです。許可される値は、従来を表す 0、連続 を表す 1、または インターリーブ を表す 2 です。セクション14.6.5「InnoDB での AUTO_INCREMENT 処理」では、これらのモードの特性について説明します。

    この変数のデフォルトは、1 (連続ロックモード) です。

  • innodb_buffer_pool_dump_at_shutdown

    コマンド行形式--innodb-buffer-pool-dump-at-shutdown=#
    導入5.6.3
    システム変数innodb_buffer_pool_dump_at_shutdown
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF

    次回再起動時のウォームアッププロセスの時間を短縮するために、MySQL サーバーのシャットダウン時に、InnoDB のバッファープールにキャッシュされるページを記録するかどうかを指定します。一般に、innodb_buffer_pool_load_at_startup と組み合わせて使用されます。

    関連情報については、セクション14.13.1.5「再起動を高速化するための InnoDB バッファープールのプリロード」を参照してください。

  • innodb_buffer_pool_dump_now

    コマンド行形式--innodb-buffer-pool-dump-now=#
    導入5.6.3
    システム変数innodb_buffer_pool_dump_now
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF

    InnoDB のバッファープールにキャッシュされるページをすぐに記録します。一般に、innodb_buffer_pool_load_now と組み合わせて使用されます。

    関連情報については、セクション14.13.1.5「再起動を高速化するための InnoDB バッファープールのプリロード」を参照してください。

  • innodb_buffer_pool_filename

    コマンド行形式--innodb-buffer-pool-filename=file
    導入5.6.3
    システム変数innodb_buffer_pool_filename
    スコープグローバル
    動的はい
    ファイル名
    デフォルトib_buffer_pool

    innodb_buffer_pool_dump_at_shutdown または innodb_buffer_pool_dump_now で生成されるテーブルスペース ID およびページ ID のリストを保持するファイルの名前を指定します。テーブルスペース ID およびページ ID は、space, page_id という形式で保存されます。デフォルトでは、このファイルは InnoDB データディレクトリに配置されます。

    関連情報については、セクション14.13.1.5「再起動を高速化するための InnoDB バッファープールのプリロード」を参照してください。

  • innodb_buffer_pool_instances

    コマンド行形式--innodb-buffer-pool-instances=#
    システム変数innodb_buffer_pool_instances
    スコープグローバル
    動的いいえ
    数値
    デフォルト (その他, ≥ 5.6.6)8
    デフォルト (Windows, 32 ビットプラットフォーム, ≥ 5.6.6)(autosized)
    デフォルト (≤ 5.6.5)1
    最小値1
    最大値64

    InnoDBバッファープールが分割される領域の数です。バッファープールが数 G バイトの範囲にあるシステムでは、バッファープールを個別のインスタンスに分割すると、キャッシュされたページに対して異なるスレッドが読み取りおよび書き込みを行うときの競合が減るため、並列性が向上する場合があります。バッファープールに格納される各ページまたはバッファープールから読み取られる各ページは、ハッシュ関数を使用して、バッファープールインスタンスのいずれかにランダムに割り当てられます。各バッファープールは、独自の空きリスト、フラッシュリストLRU、およびバッファープールに接続されたその他のすべてのデータ構造を管理し、独自のバッファープール相互排他ロックによって保護されます。

    このオプションは、innodb_buffer_pool_size を 1G バイト以上のサイズに設定した場合にのみ有効になります。指定した合計サイズは、すべてのバッファープール間で分割されます。最高の効率を得るには、innodb_buffer_pool_instancesinnodb_buffer_pool_size の組み合わせを、各バッファープールインスタンスが少なくとも 1G バイトになるように指定します。

    MySQL 5.6.6 より前では、デフォルトは 1 です。MySQL 5.6.6 の時点では、デフォルトは 8 です。ただし、32 ビットの Windows システムでは、デフォルトは innodb_buffer_pool_size の値に依存します。

    • innodb_buffer_pool_size が 1.3G バイトよりも大きい場合は、innodb_buffer_pool_instances のデフォルトが innodb_buffer_pool_size/128M バイトになり、チャンクごとに個別のメモリー割り当てリクエストを持ちます。32 ビット版 Windows で単一のバッファープールで必要となる連続したアドレス空間を割り当てることができないという重大なリスクが存在する境界として、1.3G バイトが選択されました。

    • それ以外の場合、デフォルトは 1 です。

  • innodb_buffer_pool_load_abort

    コマンド行形式--innodb-buffer-pool-load-abort=#
    導入5.6.3
    システム変数innodb_buffer_pool_load_abort
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF

    innodb_buffer_pool_load_at_startup または innodb_buffer_pool_load_now でトリガーされる InnoDB のバッファープールの内容をリストアするプロセスを中断します。

    関連情報については、セクション14.13.1.5「再起動を高速化するための InnoDB バッファープールのプリロード」を参照してください。

  • innodb_buffer_pool_load_at_startup

    コマンド行形式--innodb-buffer-pool-load-at-startup=#
    導入5.6.3
    システム変数innodb_buffer_pool_load_at_startup
    スコープグローバル
    動的いいえ
    ブール
    デフォルトOFF

    MySQL サーバーの起動時に、以前に保持されたときと同じページをロードすることで、InnoDB のバッファープールが自動的にウォームアップされるように指定します。一般に、innodb_buffer_pool_dump_at_shutdown と組み合わせて使用されます。

    関連情報については、セクション14.13.1.5「再起動を高速化するための InnoDB バッファープールのプリロード」を参照してください。

  • innodb_buffer_pool_load_now

    コマンド行形式--innodb-buffer-pool-load-now=#
    導入5.6.3
    システム変数innodb_buffer_pool_load_now
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF

    サーバーの再起動を待機せずにデータページのセットをロードすることで、InnoDB のバッファープールをすぐにウォームアップします。ベンチマーク時にキャッシュメモリーを既知の状態に戻したり、レポートやメンテナンスのためにクエリーを実行したあとに、MySQL サーバーの通常のワークロードを再開する準備をしたりする際に役立ちます。

    関連情報については、セクション14.13.1.5「再起動を高速化するための InnoDB バッファープールのプリロード」を参照してください。

  • innodb_buffer_pool_size

    コマンド行形式--innodb-buffer-pool-size=#
    システム変数innodb_buffer_pool_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト134217728
    最小値5242880
    最大値 (64 ビットプラットフォーム)2**64-1
    最大値 (32 ビットプラットフォーム)2**32-1

    InnoDB がテーブルおよびインデックスのデータをキャッシュするメモリー領域であるバッファープールのサイズ (バイト単位) です。デフォルト値は 128M バイトです。最大値は、CPU アーキテクチャーによって異なります。最大値は、32 ビットシステムでは 4294967295 (232-1)、64 ビットシステムでは 18446744073709551615 (264-1) です。32 ビットシステムでは、CPU アーキテクチャーおよびオペレーティングシステムに、指定された最大値よりも小さい実用的な最大サイズが課されている可能性があります。バッファープールのサイズが 1G バイトよりも大きい場合に、innodb_buffer_pool_instances を 1 よりも大きい値に設定すると、高負荷のサーバーで拡張性を改善できます。

    この値を大きく設定するほど、テーブル内の同じデータに複数回アクセスするために必要なディスク I/O が少なくなります。専用のデータベースサーバーでは、これを最大でマシンの物理メモリーサイズの 80% まで設定することがあります。次のようなその他の問題が発生した場合は、この値を小さくする準備をしてください。

    • 物理メモリーが競合すると、オペレーティングシステムでページングが発生する可能性があります。

    • InnoDB では、割り当てられた領域の合計が指定されたサイズよりも約 10% 大きくなるように、バッファーおよび制御構造用に追加のメモリーが予約されています。

    • アドレス空間は隣接しているはすです。これにより、Windows システムで特定のアドレスにロードする DLL に関する問題が発生する可能性があります。

    • バッファープールを初期化する時間は、ほぼそのサイズに比例しています。大規模なインストールでは、この初期化時間が重要となる場合もあります。たとえば、最新の Linux x86_64 サーバーで 10G バイトのバッファープールを初期化するには、約 6 秒かかります。セクション8.9.1「InnoDB バッファープール」を参照してください。

  • innodb_change_buffer_max_size

    コマンド行形式--innodb-change-buffer-max-size=#
    導入5.6.2
    システム変数innodb_change_buffer_max_size
    スコープグローバル
    動的はい
    数値
    デフォルト25
    最小値0
    最大値50

    バッファープールの合計サイズの割合として示した、InnoDB の変更バッファーの最大サイズです。この値は、MySQL サーバーで頻繁に挿入、更新、および削除アクティビティーが発生する場合は大きくし、MySQL サーバーでレポート用に使用されるデータが変更されない場合は小さくするとよいでしょう。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_change_buffering

    コマンド行形式--innodb-change-buffering=#
    システム変数innodb_change_buffering
    スコープグローバル
    動的はい
    列挙
    デフォルトall
    有効な値

    inserts

    deletes

    purges

    changes

    all

    none

    InnoDBバッファリングの変更 (I/O 操作を連続して実行できるように、セカンダリインデックスへの書き込み操作を遅延させる最適化) を実行するかどうかを指定します。許可される値は inserts (挿入操作のバッファリング)、deletes (削除操作のバッファリング。厳密に言えば、パージ操作時にあとで削除するインデックスレコードにマークを付ける書き込み)、changes (挿入操作および削除マーク操作のバッファリング)、purges (パージ操作のバッファリング。削除されたインデックスエントリのガベージコレクションが最終的に実行される書き込み)、all (挿入、削除マーク、パージ操作のバッファリング)、および none (操作のバッファリングなし) です。デフォルトは all です。詳細については、セクション14.13.4「InnoDB 変更バッファリングの構成」を参照してください。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_checksum_algorithm

    コマンド行形式--innodb-checksum-algorithm=#
    導入5.6.3
    システム変数innodb_checksum_algorithm
    スコープグローバル
    動的はい
    列挙
    デフォルト (≥ 5.6.7)innodb
    デフォルト (5.6.6)crc32
    デフォルト (≤ 5.6.5)innodb
    有効な値

    innodb

    crc32

    none

    strict_innodb

    strict_crc32

    strict_none

    InnoDB の各テーブルスペースの各ディスクブロックに格納されているチェックサムを生成および検証する方法を指定します。

    MySQL 5.6.3 の時点で innodb_checksums オプションは、innodb_checksum_algorithm で置き換えられました。次の値は、互換性を保つために提供されています。

    • innodb_checksum_algorithm=innodbinnodb_checksums=ON と同じです。

    • innodb_checksum_algorithm=noneinnodb_checksums=OFF と同じです。

    競合を回避するには、構成ファイルおよび MySQL 起動スクリプトから innodb_checksums への参照を削除します。

    innodb は、すべての MySQL バージョンとの下位互換性があります。値 crc32 では、より高速に、変更されたすべてのブロックのチェックサムを計算し、ディスク読み取りごとにチェックサムをチェックするアルゴリズムが使用されます。値 none では、ブロックデータに基づいて値が計算されるのではなく、チェックサムフィールドに定数値が書き込まれます。テーブルスペース内のブロックは、古い値、新しい値、およびチェックサムなしの値を混在させて使用でき、データが更新されるにつれ徐々に更新されます。テーブルスペース内のブロックが crc32 アルゴリズムを使用するように変更されたあとは、関連付けられたテーブルを以前のバージョンの MySQL で読み取ることはできません。

    strict_* 形式の機能は、innodbcrc32、および none と同じです。ただし、InnoDB は、同じテーブルスペース内でチェックサム値の混在が発生した場合に停止します。これらのオプションを完全に新しいインスタンスで使用するだけで、はじめてでもすべてのテーブルスペースを設定できます。strict_* 設定では、ディスクの読み取り時に新しいチェックサム値と古いチェックサム値の両方を受け入れるために、その両方を計算する必要がないため、多少高速になります。

    次の表には、noneinnodbcrc32 オプション値、およびそれぞれに対応する strict_ オプション値間の相違点を示します。noneinnodb、および crc32 では、特定のタイプのチェックサム値が各データブロックに書き込まれますが、互換性を保つために、読み取り操作中にブロックを検証する際に、その他のチェックサム値のいずれかが受け入れられます。strict_ 形式の各パラメータでは、1 種類のチェックサムのみが認識されます。これにより、検証が高速になりますが、インスタンス内のすべての InnoDB データファイルが同じ innodb_checksum_algorithm 値で作成される必要があります。

    表 14.7 innodb_checksum_algorithm で許可される設定

    生成されるチェックサム (書き込み時)許可されるチェックサム (読み取り時)
    none定数。noneinnodb、または crc32 で生成されるチェックサムのいずれか。
    innodbソフトウェアで InnoDB の元のアルゴリズムを使用して計算されたチェックサム。noneinnodb、または crc32 で生成されるチェックサムのいずれか。
    crc32crc32 アルゴリズムを使用して計算されたチェックサム (ハードウェアの支援を得て実行される可能性もあります)。noneinnodb、または crc32 で生成されるチェックサムのいずれか。
    strict_none定数none で生成されるチェックサムのみ。
    strict_innodbソフトウェアで InnoDB の元のアルゴリズムを使用して計算されたチェックサム。innodb で生成されるチェックサムのみ。
    strict_crc32crc32 アルゴリズムを使用して計算されたチェックサム (ハードウェアの支援を得て実行される可能性もあります)。crc32 で生成されるチェックサムのみ。

    innodb_checksum_algorithm のデフォルト値は MySQL 5.6.6 で innodb から crc32 に変更されましたが、以前の MySQL バージョンへのダウングレード中の InnoDB データファイルの互換性向上のため、および MySQL Enterprise Backup で使用するために 5.6.7 で innodb に戻されました。検出された制限には、次のものが含まれます。

    • CRC32 チェックサムを含む .ibd ファイルは、5.6.3 より前の MySQL バージョンへのダウングレード中に問題が発生する可能性があります。MySQL 5.6.3 以降では、ディスクからブロックを読み取るとき、そのブロックの新しいチェックサム値と古いチェックサム値のどちらも正しいとして認識します。それにより、アルゴリズムの設定には関係なく、アップグレードおよびダウングレード中にそのデータブロックの互換性を保証します。新しいチェックサム値で書き込まれたデータが 5.6.3 より前のレベルの MySQL によって処理された場合は、破損しているとしてレポートされる可能性があります。

    • 3.8.0 までのバージョンの MySQL Enterprise Backup は、CRC32 チェックサムを使用するテーブルスペースのバックアップをサポートしていません。MySQL Enterprise Backup は、CRC32 チェックサムのサポートを 3.8.1 で (いくつかの制限付きで) 追加しています。詳細は、MySQL Enterprise Backup 3.8.1 の変更履歴を参照してください。

    crc32 チェックサムアルゴリズムに関する追加情報については、セクション14.13.15「チェックサムの高速化のための CRC32 チェックサムアルゴリズムの使用」を参照してください。

  • innodb_checksums

    コマンド行形式--innodb-checksums
    非推奨5.6.3
    システム変数innodb_checksums
    スコープグローバル
    動的いいえ
    ブール
    デフォルトON

    InnoDB では、ディスクから読み取られるすべてのテーブルスペースページ上でチェックサム検証を使用することで、ハードウェアの障害やデータファイルの破損に対する追加のフォールトトレランスを実現できます。この検証はデフォルトで有効になっています。特殊な状況 (ベンチマークの実行時など) では、このような追加の安全機能は --skip-innodb-checksums を使用して無効にすることができます。innodb_checksum_algorithm を使用すると、チェックサムを計算する方法を指定できます。

    MySQL 5.6.3 以降では、このオプションは非推奨となり、innodb_checksum_algorithm で置き換えられました。innodb_checksum_algorithm=innodbinnodb_checksums=ON (デフォルト) と同じです。innodb_checksum_algorithm=noneinnodb_checksums=OFF と同じです。innodb_checksum_algorithm との競合を回避するために、構成ファイルおよび起動スクリプトからすべての innodb_checksums オプションを削除してください。innodb_checksums=OFF によって自動的に innodb_checksum_algorithm=none が設定され、innodb_checksums=ON は無視され、innodb_checksum_algorithm のその他の設定でオーバーライドされます。

  • innodb_cmp_per_index_enabled

    コマンド行形式--innodb-cmp-per-index-enabled=#
    導入5.6.7
    システム変数innodb_cmp_per_index_enabled
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF
    有効な値

    OFF

    ON

    INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX テーブルでインデックスごとの圧縮関連の統計を有効にします。これらの統計を収集すると負荷が高くなるため、このオプションは、InnoDB圧縮済みテーブルに関連するパフォーマンスチューニング時に開発、テスト、またはスレーブのインスタンス上でのみ有効にしてください。

  • innodb_commit_concurrency

    コマンド行形式--innodb-commit-concurrency=#
    システム変数innodb_commit_concurrency
    スコープグローバル
    動的はい
    数値
    デフォルト0
    最小値0
    最大値1000

    同時にコミットできるスレッドの数です。値を 0 (デフォルト) にすると、任意の数のトランザクションを同時にコミットすることが許可されます。

    innodb_commit_concurrency の値は、実行時にゼロからゼロ以外 (またはその逆) に変更できません。ゼロ以外の値から別のゼロ以外の値に変更することはできます。

  • innodb_compression_failure_threshold_pct

    コマンド行形式--innodb-compression-failure-threshold-pct=#
    導入5.6.7
    システム変数innodb_compression_failure_threshold_pct
    スコープグローバル
    動的はい
    数値
    デフォルト5
    最小値0
    最大値100

    高負荷での圧縮の失敗を回避するために、圧縮されたページ内のパディングの追加が MySQL で開始されるカットオフポイントを設定します。値をゼロにすると、圧縮の効率性をモニターするメカニズムが無効になり、パディングの量が動的に調整されます。

  • innodb_compression_level

    コマンド行形式--innodb-compression-level=#
    導入5.6.7
    システム変数innodb_compression_level
    スコープグローバル
    動的はい
    数値
    デフォルト6
    最小値0
    最大値9

    InnoDB圧縮されたテーブルおよびインデックスで使用される zlib 圧縮のレベルを指定します。

  • innodb_compression_pad_pct_max

    コマンド行形式--innodb-compression-pad-pct-max=#
    導入5.6.7
    システム変数innodb_compression_pad_pct_max
    スコープグローバル
    動的はい
    数値
    デフォルト50
    最小値0
    最大値75

    圧縮された各ページ内の空き領域として予約できる最大の割合を指定します。これにより、圧縮されたテーブルまたはインデックスが更新され、データが再度圧縮される可能性があるときに、ページ内のデータおよび変更ログを再編成する余地が得られます。innodb_compression_failure_threshold_pct がゼロ以外の値に設定され、圧縮エラーの比率がカットオフポイントを超えたときにのみ適用されます。

  • innodb_concurrency_tickets

    コマンド行形式--innodb-concurrency-tickets=#
    システム変数innodb_concurrency_tickets
    スコープグローバル
    動的はい
    数値
    デフォルト (≥ 5.6.6)5000
    デフォルト (≤ 5.6.5)500
    最小値1
    最大値4294967295

    同時に InnoDB に入ることができるスレッドの数を決定します。スレッドが InnoDB に入ろうとしたときに、すでにスレッド数が並列実行の制限に達している場合は、そのスレッドがキューに配置されます。スレッドが InnoDB に入ることが許可されている場合は、innodb_concurrency_tickets の値に等しい数の空きチケットが付与され、スレッドはそのチケットを使い果たすまで自由に InnoDB に出入りすることができます。それ以降は、スレッドが次に InnoDB に入ろうとしたときに、再度並列実行チェックの対象となります (キューに入る対象となる可能性もあります)。デフォルト値は、MySQL 5.6.6 の時点では 5000、それよりも前では 500 です。

    innodb_concurrency_tickets 値を小さくすると、1、2 行しか処理する必要のない小規模なトランザクションと、多数の行を処理する大規模なトランザクションが競合する可能性が高くなります。innodb_concurrency_tickets 値を小さくする欠点は、大規模なトランザクションが完了するまでに何回もキュー間をループする必要があるため、タスクを完了するために必要な時間が長くなる点です。

    innodb_concurrency_tickets 値を大きくすると、大規模なトランザクションで (innodb_thread_concurrency で制御される) キューの終了時の位置を待機する時間が短くなり、行を取得する時間が長くなります。また、大規模なトランザクションでは、タスクを完了するために必要なキューとの間の移動も少なくなります。innodb_concurrency_tickets 値を大きくする欠点は、同時に実行する大規模なトランザクションの数が非常に多くなることで、小規模なトランザクションが実行されるまでの待機時間が長くなるため、枯渇する可能性がある点です。

    innodb_thread_concurrency 値をゼロ以外にすると、大規模なトランザクションと小規模なトランザクション間の適切なバランスを見つけるために、innodb_concurrency_tickets 値を上下に調整する必要がある場合があります。SHOW ENGINE INNODB STATUS レポートには、キューを通過する現時点で実行中のトランザクション用に残されているチケットの数が表示されます。このデータは、INFORMATION_SCHEMA.INNODB_TRX テーブルの TRX_CONCURRENCY_TICKETS カラムから取得することもできます。

    詳細は、セクション14.13.5「InnoDB のスレッド並列性の構成」を参照してください。

  • innodb_data_file_path

    コマンド行形式--innodb-data-file-path=name
    システム変数innodb_data_file_path
    スコープグローバル
    動的いいえ
    文字列
    デフォルト (≥ 5.6.7)ibdata1:12M:autoextend
    デフォルト (≤ 5.6.6)ibdata1:10M:autoextend

    InnoDB の各データファイルへのパスとそれらのサイズです。各データファイルへの完全ディレクトリパスは、ここに指定された各パスに innodb_data_home_dir を結合することで形成されます。サイズ値に KM、または G を追加することで、ファイルサイズが K バイト、M バイト、または G バイト (1024M バイト) で指定されます。データファイルのサイズをキロバイト (K バイト) で指定する場合は、1024 の倍数で指定してください。それ以外の場合は、K バイト値はもっとも近いメガバイト (M バイト) の境界で丸められます。ファイルサイズの合計は、わずかに 10M バイトを上回る大きさにする必要があります。innodb_data_file_path を指定しない場合は、デフォルトの動作で、ibdata1 という名前の単一の自動拡張データファイルが 12M バイトをわずかに上回る大きさで作成されます。各ファイルのサイズ制限は、オペレーティングシステムによって決定されます。大きいファイルをサポートするオペレーティングシステムでは、4G バイトよりも大きいファイルサイズを設定できます。データファイルとして生のディスクパーティションを使用することもできます。InnoDBテーブルスペースファイルの構成についての詳細は、セクション14.3「InnoDB の構成」を参照してください。

  • innodb_data_home_dir

    コマンド行形式--innodb-data-home-dir=path
    システム変数innodb_data_home_dir
    スコープグローバル
    動的いいえ
    ディレクトリ名

    システムテーブルスペース内のすべての InnoDBデータファイルのディレクトリパスに共通する部分です。この設定によって、innodb_file_per_table を有効にしたときの file-per-table テーブルスペースの場所は影響を受けません。デフォルト値は、MySQL の data ディレクトリです。値を空の文字列として指定した場合は、innodb_data_file_path 内で完全なファイルパスを使用できます。

  • innodb_disable_sort_file_cache

    コマンド行形式--innodb-disable-sort-file-cache=#
    導入5.6.4
    システム変数innodb_disable_sort_file_cache
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF

    この変数を有効にすると、マージソート一時ファイル用のオペレーティングシステムファイルシステムのキャッシュが無効になります。その結果、このようなファイルが O_DIRECT の同等のものとともに開きます。この変数は MySQL 5.6.4 で追加されました。

  • innodb_doublewrite

    コマンド行形式--innodb-doublewrite
    システム変数innodb_doublewrite
    スコープグローバル
    動的いいえ
    ブール
    デフォルトON

    この変数を有効にすると (デフォルト)、InnoDB にすべてのデータが 2 回 (まず二重書き込みバッファー、次に実際のデータファイルに) 格納されます。データの整合性や失敗の可能性の懸念より、ベンチマークや最高のパフォーマンスが必要なケースでは、--skip-innodb_doublewrite を使用すれば、この変数を無効にすることができます。

  • innodb_fast_shutdown

    コマンド行形式--innodb-fast-shutdown[=#]
    システム変数innodb_fast_shutdown
    スコープグローバル
    動的はい
    数値
    デフォルト1
    有効な値

    0

    1

    2

    InnoDBシャットダウンモードです。この値を 0 にすると、InnoDB低速シャットダウン、完全なパージ、および挿入バッファーのマージを実行してから、シャットダウンします。この値を 1 (デフォルト) にすると、InnoDB はシャットダウン時に、これらの操作をスキップします。このプロセスは、高速シャットダウンと呼ばれます。この値を 2 にすると、InnoDB は MySQL がクラッシュした場合と同様に、そのログをフラッシュし、コールドシャットダウンを実行します。コミットされていないトランザクションは失われませんが、クラッシュリカバリ操作によって次回の起動時間が長くなります。

    低速シャットダウンには数分間かかる可能性があり、大量のデータがバッファーに存在する極端なケースでは、数時間かかる可能性もあります。MySQL のメジャーリリース間でアップグレードまたはダウングレードを行う前には、アップグレードプロセスによってファイル形式が更新される場合に備えて、すべてのデータファイルが完全に準備されるように、低速シャットダウン技術を使用してください。

    データが破損するリスクがある場合に、完全な最速のシャットダウンを行うには、緊急事態またはトラブルシューティングの状況で innodb_fast_shutdown=2 を使用してください。

  • innodb_file_format

    コマンド行形式--innodb-file-format=#
    システム変数innodb_file_format
    スコープグローバル
    動的はい
    文字列
    デフォルトAntelope
    有効な値

    Antelope

    Barracuda

    新しい InnoDB テーブルで使用されるファイル形式です。現在は、Antelope および Barracuda がサポートされています。これは、独自のテーブルスペースを持つテーブルにのみ適用されるため、これを有効にするには、innodb_file_per_table が有効になっている必要があります。テーブルの圧縮などの特定の InnoDB 機能を使用するには、Barracuda ファイル形式が必要です。

    InnoDB のテーブル (ALGORITHM=COPY) を再作成する ALTER TABLE 操作では、現在の innodb_file_format 設定が使用される (前述の状況が適用される) ことに注意してください。

  • innodb_file_format_check

    コマンド行形式--innodb-file-format-check=#
    システム変数innodb_file_format_check
    スコープグローバル
    動的いいえ
    ブール
    デフォルトON

    この変数をサーバーの起動時に 1 または 0 に設定すると、InnoDBシステムテーブルスペースファイル形式タグ (AntelopeBarracuda など) をチェックするかどうかを有効または無効にすることができます。チェックされたタグが最新バージョンの InnoDB でサポートされているよりも大きい場合は、エラーが発生し、InnoDB は起動されません。このタグの方が大きくない場合は、InnoDB によって innodb_file_format_max の値がファイル形式タグに設定されます。

    注記

    デフォルト値が ON または OFF と表示されることがあるにもかかわらず、このオプションを構成ファイルまたはコマンド行でオンまたはオフに切り替えるには、常に数値 1 または 0 を使用します。

  • innodb_file_format_max

    コマンド行形式--innodb-file-format-max=#
    システム変数innodb_file_format_max
    スコープグローバル
    動的はい
    文字列
    デフォルトAntelope
    有効な値

    Antelope

    Barracuda

    サーバーの起動時に InnoDB によって、この変数の値がシステムテーブルスペースファイル形式タグ (AntelopeBarracuda など) に設定されます。サーバーで大きいファイル形式のテーブルが作成されたり、開かれたりすると、innodb_file_format_max の値がそのファイル形式に設定されます。

  • innodb_file_per_table

    コマンド行形式--innodb-file-per-table
    システム変数innodb_file_per_table
    スコープグローバル
    動的はい
    ブール
    デフォルト (≥ 5.6.6)ON
    デフォルト (≤ 5.6.5)OFF

    innodb_file_per_table が有効になっている (5.6.6 以上のデフォルト) 場合、InnoDB では、新たに作成された各テーブルのデータおよびインデックスがシステムテーブルスペースではなく、個別の .ibd ファイルに格納されます。これらの InnoDB テーブル用のストレージは、テーブルが削除されたり、切り捨てられたりすると再利用されます。このように設定すると、テーブルの圧縮などのその他のいくつかの InnoDB 機能が有効になります。このような機能、および file-per-table テーブルスペースを使用する利点および欠点についての詳細は、セクション14.5.2「InnoDB File-Per-Table モード」を参照してください。

    ALTER TABLE でテーブルが再作成されるケース (ALGORITHM=COPY) では、innodb_file_per_table を有効にすることは、ALTER TABLE 操作によって InnoDB テーブルがシステムテーブルスペースから個々の .ibd ファイルに移動されることも意味することに注意してください。

    innodb_file_per_table を無効にすると、InnoDB ではすべてのテーブルおよびインデックス用のデータが、システムテーブルスペースを構成する ibdata ファイルに格納されます。このように設定すると、DROP TABLETRUNCATE TABLE などの操作で、ファイルシステム操作のパフォーマンスオーバーヘッドが削減されます。これは、ストレージデバイス全体が MySQL データ専用になっているサーバー環境に最適です。システムテーブルスペースは縮小されず、インスタンス内のすべてのデータベースにわたって共有されないため、innodb_file_per_table=OFF のときは、領域が制約されているシステムで一時データを大量にロードすることは回避してください。このような場合は、領域を再利用するためにインスタンス全体を削除できるように、個別のインスタンスを設定します。

    MySQL 5.6.6 の時点では、デフォルトで innodb_file_per_table が有効になっています。それよりも前では、無効になっています。MySQL 5.5 または 5.1 との下位互換性が懸念事項となっている場合は、これを無効にすることを検討してください。これにより、ALTER TABLE によって InnoDB テーブルがシステムテーブルスペースから個々の .ibd ファイルに移動することが回避されます。

    innodb_file_per_table は動的であり、SET GLOBAL を使用して ON または OFF に設定できます。このパラメータは、MySQL 構成ファイル (my.cnf または my.ini) でも設定できますが、このためにはサーバーをシャットダウンしてから再起動する必要があります。

    このパラメータの値を動的に変更するには、SUPER 権限が必要です。動的に変更すると、すべての接続の操作がすぐに影響を受けます。

  • innodb_flush_log_at_timeout

    導入5.6.6
    システム変数innodb_flush_log_at_timeout
    スコープグローバル
    動的はい
    数値
    デフォルト1
    最小値1
    最大値2700

    ログを N 秒ごとに書き込んで、フラッシュします。innodb_flush_log_at_timeout は MySQL 5.6.6 で導入されました。フラッシュを減らし、バイナリロググループのコミット時のパフォーマンスへの影響を回避するために、フラッシュ間のタイムアウト期間を長くすることができます。MySQL 5.6.6 よりも前では、フラッシュの頻度は 1 秒ごとに 1 回でした。innodb_flush_log_at_timeout のデフォルト設定も 1 秒ごとに 1 回です。

  • innodb_flush_log_at_trx_commit

    コマンド行形式--innodb-flush-log-at-trx-commit[=#]
    システム変数innodb_flush_log_at_trx_commit
    スコープグローバル
    動的はい
    列挙
    デフォルト1
    有効な値

    0

    1

    2

    コミット操作に対する厳密な ACID コンプライアンスと、コミット関連の I/O 操作が再編成およびバッチ処理されるときに実現可能な高いパフォーマンスとの間のバランスを制御します。デフォルト値を変更するとパフォーマンスを改善できますが、クラッシュ時にトランザクションが最大で 1 秒間失われる可能性があります。

    • 完全に ACID コンプライアンスに従うには、デフォルト値の 1 を使用する必要があります。この値を使用すると、トランザクションコミットのたびに、InnoDBログバッファーの内容がログファイルに書き込まれ、ログファイルがディスクにフラッシュされます。

    • 値を 0 にすると、約 1 秒ごとに 1 回、InnoDB のログバッファーの内容がログファイルに書き込まれ、ログファイルがディスクにフラッシュされます。ログバッファーからログファイルに書き込みは、トランザクションコミット時には実行されません。プロセスのスケジューリングの問題が原因で、1 秒ごとに 1 回のフラッシュが毎秒発生する 100% の保証はありません。ディスク操作へのフラッシュは約 1 秒ごとに 1 回しか発生しないため、任意の mysqld プロセスがクラッシュすると、トランザクションが最大で 1 秒間失われる可能性があります。

    • 値を 2 にすると、トランザクションコミットのたびに、InnoDB のログバッファーの内容がログファイルに書き込まれ、約 1 秒ごとに 1 回ログファイルがディスクにフラッシュされます。プロセスのスケジューリングの問題が原因で、1 秒ごとに 1 回のフラッシュが毎秒発生する 100% の保証はありません。ディスク操作へのフラッシュは約 1 秒ごとに 1 回しか発生しないため、オペレーティングシステムがクラッシュしたり、停電が発生したりすると、トランザクションが最大で 1 秒間失われる可能性があります。

    • MySQL 5.6.6 の時点では、InnoDB でのログフラッシュの頻度が innodb_flush_log_at_timeout で制御されます。これにより、ログフラッシュの頻度を N 秒間に設定できます (ここで、N1 ... 2700 で、デフォルト値は 1 です)。ただし、任意の mysqld プロセスがクラッシュすると、トランザクションが最大で N 秒間消失する可能性があります。

    • innodb_flush_log_at_trx_commit の設定とは関係なく、DDL の変更やその他の InnoDB アクティビティーによって、InnoDB のログがフラッシュされます。

    • InnoDBクラッシュリカバリは、innodb_flush_log_at_trx_commit の設定に関係なく機能します。トランザクションは完全に適用されるか、完全に消去されるかのいずれかです。

    トランザクションで InnoDB が使用されるレプリケーションセットアップの持続性および一貫性を保つ場合:

    • バイナリロギングが有効になっている場合は、sync_binlog=1 を設定します。

    • 常に innodb_flush_log_at_trx_commit=1 を設定します。

    注意

    多くのオペレーティングシステムや一部のディスクハードウェアは、ディスクへのフラッシュ操作を行なったと欺きます。フラッシュが行われていなくても、行われたと mysqld に通知される可能性があります。そのため、1 を設定してもトランザクションの持続性は保証されず、最悪のケースでは、停電によって InnoDB のデータが破損する可能性もあります。バッテリーバックアップのディスクキャッシュを SCSI ディスクコントローラ内やディスク自体で使用すると、ファイルフラッシュの速度が上がり、操作が安全になります。ハードウェアキャッシュ内でディスク書き込みのキャッシュを無効にするために、Unix コマンド hdparm を使用してみたり、ハードウェアベンダー固有のその他のコマンドを使用したりすることもできます。

  • innodb_flush_method

    コマンド行形式--innodb-flush-method=name
    システム変数innodb_flush_method
    スコープグローバル
    動的いいえ
    文字列
    デフォルト (Windows)async_unbuffered
    デフォルト (Unix)fsync
    有効な値 (Unix, ≥ 5.6.7)

    fsync

    O_DSYNC

    O_DIRECT

    O_DIRECT_NO_FSYNC

    有効な値 (Unix, ≤ 5.6.6)

    fsync

    O_DSYNC

    O_DIRECT

    InnoDBデータファイルおよびログファイルにデータをフラッシュする際に使用される方法を定義します。これにより、I/O スループットが影響を受ける可能性があります。この変数は、Unix および Linux システムでのみ構成可能です。Windows システムでは、フラッシュ方法は常に async_unbuffered であり、変更できません。

    innodb_flush_method オプションの内容は、次のとおりです。

    • fsync: InnoDBfsync() システムコールを使用して、データファイルとログファイルの両方をフラッシュします。fsync はデフォルト設定です。

    • O_DSYNC: InnoDB は、O_SYNC を使用してログファイルを開いてフラッシュし、fsync() を使用してデータファイルをフラッシュします。さまざまな種類の Unix で問題が発生しているため、InnoDB では直接 O_DSYNC が使用されません。

    • O_DIRECT: InnoDB は、O_DIRECT (Solaris では directio()) を使用してデータファイルを開き、fsync() を使用してデータファイルとログファイルの両方をフラッシュします。このオプションは、一部の GNU/Linux バージョン、FreeBSD、および Solaris で使用可能です。

    • O_DIRECT_NO_FSYNC: InnoDB は、I/O のフラッシュ時に O_DIRECT を使用しますが、後続の fsync() システムコールはスキップします。この設定は、一部のタイプのファイルシステムには適していますが、その他には適していません。たとえば、XFS には適していません。たとえば、使用中のファイルシステムですべてのファイルメタデータを保持するために、fsync() が必要であるのかどうかが不明な場合は、代わりに O_DIRECT を使用してください。このオプションは MySQL 5.6.7 (Bug #11754304、Bug #45892) で導入されました。

    各設定によるパフォーマンスへの影響度は、ハードウェア構成およびワークロードによって異なります。使用する設定を決定したり、デフォルト設定のままにするかどうかを決定したりするには、特定の構成でベンチマークを実施します。設定ごとに fsync() 呼び出しの全体数を確認するには、Innodb_data_fsyncs ステータス変数を調査します。ワークロードに読み取り操作と書き込み操作を混在させると、一部の設定での実行が影響を受ける可能性があります。たとえば、ハードウェア RAID コントローラおよびバッテリーでバックアップされる書き込みキャッシュが搭載されたシステムでは、InnoDB のバッファープールとオペレーティングシステムのファイルシステムキャッシュ間での二重バッファリングを回避する際に、O_DIRECT が役立つことがあります。InnoDB のデータファイルとログファイルが SAN 上に配置されている一部のシステムでは、大部分の SELECT ステートメントを含む読み取り負荷の高いワークロードで、デフォルト値または O_DSYNC の速度が速くなる可能性があります。このパラメータは、必ず、本番環境が反映されたハードウェアおよびワークロードでテストしてください。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_flush_neighbors

    コマンド行形式--innodb-flush-neighbors
    導入5.6.3
    システム変数innodb_flush_neighbors
    スコープグローバル
    動的はい
    列挙
    デフォルト1
    有効な値

    0

    1

    2

    InnoDB のバッファープールからページをフラッシュすると、同じエクステント内のその他のダーティーページもフラッシュされるかどうかを指定します。

    • デフォルト値の 1 では、バッファープールから同じエクステント内の連続するダーティーページがフラッシュされます。

    • 0 を設定すると、innodb_flush_neighbors がオフになり、その他のダーティーページはバッファープールからフラッシュされません。

    • 2 を設定すると、同じエクステント内のダーティーページがバッファープールからフラッシュされます。

    テーブルデータが従来の HDD ストレージデバイスに格納されている場合は、1 回の操作でこのような隣接ページをフラッシュすると、さまざまな時間に個々のページをフラッシュする場合と比較して、(主にディスクシーク操作の) I/O オーバーヘッドが削減されます。テーブルデータが SSD 上に格納されている場合は、シーク時間が重要な要素ではないため、この設定をオフにすれば、書き込み操作を分散できます。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_flushing_avg_loops

    コマンド行形式--innodb-flushing-avg-loops=#
    導入5.6.6
    システム変数innodb_flushing_avg_loops
    スコープグローバル
    動的はい
    数値
    デフォルト30
    最小値1
    最大値1000

    InnoDB が以前に計算されたフラッシュ状態のスナップショットを保持する繰り返しの数です。これにより、適応型フラッシュワークロードの変更に対応する速度が制御されます。この値を大きくすると、ワークロードが変化するにつれて、フラッシュ操作の速度が円滑かつ徐々に変化します。この値を小さくすると、適応型フラッシュがワークロードの変化にすばやく適応します。これにより、ワークロードが突然に増減した場合に、フラッシュアクティビティーが急増する可能性があります。

  • innodb_force_load_corrupted

    コマンド行形式--innodb-force-load-corrupted
    導入5.6.3
    システム変数innodb_force_load_corrupted
    スコープグローバル
    動的いいえ
    ブール
    デフォルトOFF

    InnoDB の起動時に、破損マークが付けられたテーブルをロードできます。トラブルシューティング時に、何も対処しなければアクセスできないデータをリカバリする際にのみ使用してください。トラブルシューティングが完了したら、この設定をオフに戻して、サーバーを再起動します。

  • innodb_force_recovery

    コマンド行形式--innodb-force-recovery=#
    システム変数innodb_force_recovery
    スコープグローバル
    動的いいえ
    数値
    デフォルト0
    最小値0
    最大値6

    クラッシュリカバリモードです。一般に、重大なトラブルシューティングの状況でのみ変更されます。指定可能な値は 0 から 6 までです。これらの値の意味および innodb_force_recovery に関する重要な情報については、セクション14.19.2「InnoDB のリカバリの強制的な実行」を参照してください。

    警告

    緊急状況でのみ、この変数を 0 よりも大きい値に設定してください。これにより、InnoDB を起動し、テーブルをダンプできるようになります。安全対策として、innodb_force_recovery を 0 よりも大きくすると、InnoDBINSERTUPDATE、または DELETE 操作が回避されます。また、5.6.15 の時点では、innodb_force_recovery の設定を 4 よりも大きくすると、InnoDB が読み取り専用モードになります。

    このような制約のために、--relay-log-info-repository=TABLE--master-info-repository=TABLE などのレプリケーションオプションによって InnoDB 内のテーブルに情報が格納されると、レプリケーション管理コマンドに失敗し、エラーが発生する可能性があります。

  • innodb_ft_aux_table

    導入5.6.4
    システム変数innodb_ft_aux_table
    スコープグローバル
    動的はい
    文字列

    FULLTEXT インデックスを含む InnoDB テーブルの修飾名を指定します。この変数は診断のために使用され、実行時にのみ設定できます。例:

    mysql> set global innodb_ft_aux_table = 'test/t1';

    この変数を起動時に設定しようとすると、mysqld: option '--innodb-ft-aux-table' cannot take an argumentエラーが発生し、起動が中止されます。この変数を db_name/table_name 形式の名前に設定すると、INFORMATION_SCHEMA テーブル INNODB_FT_INDEX_TABLEINNODB_FT_INDEX_CACHEINNODB_FT_CONFIGINNODB_FT_DELETED、および INNODB_FT_BEING_DELETED に、指定されたテーブルの検索インデックスに関する情報が表示されます。

  • innodb_ft_cache_size

    コマンド行形式--innodb-ft-cache-size=#
    導入5.6.4
    システム変数innodb_ft_cache_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト (≥ 5.6.10)8000000
    デフォルト (≥ 5.6.4, ≤ 5.6.9)32000000
    最小値1600000
    最大値80000000

    InnoDB の FULLTEXT 検索インデックスのキャッシュ用に割り当てられたメモリー量 (バイト単位) です。InnoDBFULLTEXT インデックスの作成時に、この量の解析済みドキュメントがメモリー内に保持されます。innodb_ft_cache_size のサイズ制限に達すると、インデックスの挿入および更新のみがディスクにコミットされます。innodb_ft_cache_size では、キャッシュサイズがテーブルごとに定義されます。すべてのテーブルにグローバルな制限を設定する方法については、innodb_ft_total_cache_size を参照してください。

  • innodb_ft_enable_diag_print

    コマンド行形式--innodb-ft-enable-diag-print=#
    導入5.6.4
    システム変数innodb_ft_enable_diag_print
    スコープグローバル
    動的はい
    ブール
    デフォルト (≥ 5.6.7)OFF
    デフォルト (≤ 5.6.6)ON

    追加の全文検索 (FTS) 診断の出力を有効にするかどうかを指定します。このオプションは、主に高度な FTS デバッグのために使用され、大部分のユーザーには関心がないものです。出力はエラーログに記録され、次のような情報が含まれています。

    • FTS インデックス同期の進行状況 (FTS キャッシュ制限に達したとき)。例:

      FTS SYNC for table test, deleted count: 100 size: 10000 bytes
      SYNC words: 100 
    • FTS 最適化の進行状況。例:

      FTS start optimize test
      FTS_OPTIMIZE: optimize "mysql"
      FTS_OPTIMIZE: processed "mysql" 
    • FTS インデックス構築の進行状況。例:

      Number of doc processed: 1000
    • FTS クエリーでは、クエリー解析のツリー、単語の重み、クエリーの処理時間、およびメモリーの使用状況が出力されます。例:

      FTS Search Processing time: 1 secs: 100 millisec: row(s) 10000
      Full Search Memory: 245666 (bytes), Row: 10000 
  • innodb_ft_enable_stopword

    コマンド行形式--innodb-ft-enable-stopword=#
    導入5.6.4
    システム変数innodb_ft_enable_stopword
    スコープグローバル
    動的はい
    ブール
    デフォルトON

    インデックスの作成時に、一連のストップワードInnoDBFULLTEXT インデックスに関連付けられることを指定します。innodb_ft_user_stopword_table オプションが設定されている場合は、そのテーブルからストップワードが取得されます。そうでなければ、innodb_ft_server_stopword_table オプションが設定されている場合は、そのテーブルからストップワードが取得されます。それ以外の場合は、組み込みのデフォルトストップワードセットが使用されます。

  • innodb_ft_max_token_size

    コマンド行形式--innodb-ft-max-token-size=#
    導入5.6.4
    システム変数innodb_ft_max_token_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト84
    最小値10
    最大値252

    InnoDB の FULLTEXT インデックスに格納されている単語の最大長です。この値に制限を設定すると、実在の単語ではなく、検索語句になる可能性の低い英字の任意のコレクションや長いキーワードが省略されることで、インデックスのサイズが削減されるため、クエリーの速度が上がります。

  • innodb_ft_min_token_size

    コマンド行形式--innodb-ft-min-token-size=#
    導入5.6.4
    システム変数innodb_ft_min_token_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト3
    最小値0
    最大値16

    InnoDB の FULLTEXT インデックスに格納されている単語の最小長です。この値を大きくすると、検索のコンテキストで重要となる可能性の低い一般的な単語 (ato などの英単語) が省略されることで、インデックスのサイズが削減されるため、クエリーの速度が上がります。内容で CJK (中国語、日本語、韓国語) 文字セットが使用されている場合は、値 1 を指定します。

  • innodb_ft_num_word_optimize

    コマンド行形式--innodb-ft-num-word-optimize=#
    導入5.6.4
    システム変数innodb_ft_num_word_optimize
    スコープグローバル
    動的はい
    数値
    デフォルト2000

    InnoDBFULLTEXT インデックスでの各 OPTIMIZE TABLE 操作時に処理される単語数です。全文検索インデックスを含むテーブルへの一括挿入または一括更新操作では、すべての変更を組み込むために大量のインデックスのメンテナンスが必要となる可能性があるため、それぞれが最後に終了した場所から再開する一連の OPTIMIZE TABLE ステートメントを実行するとよいでしょう。

  • innodb_ft_result_cache_limit

    コマンド行形式--innodb-ft-result-cache-limit=#
    導入5.6.13
    システム変数innodb_ft_result_cache_limit
    スコープグローバル
    動的はい
    数値
    デフォルト2000000000
    最小値1000000
    最大値 (Windows, ≥ 5.6.13, ≤ 5.6.16)2**32-1
    最大値 (Unix, 64 ビットプラットフォーム, ≥ 5.6.13, ≤ 5.6.16)2**64-1
    最大値 (Unix, 32 ビットプラットフォーム, ≥ 5.6.13, ≤ 5.6.16)2**32-1
    最大値 (≥ 5.6.17)2**32-1

    FTS クエリーごとまたはスレッドごとに、(バイト単位で定義された) InnoDB の FULLTEXT 検索 (FTS) クエリー結果のキャッシュ制限です。中間および最終の InnoDB FTS クエリー結果は、メモリー内で処理されます。InnoDB の FTS クエリー結果が非常に大きい (何百万や何億もの行数など) 場合に、過剰なメモリー消費を回避するには、innodb_ft_result_cache_limit を使用して InnoDB の FTS クエリー結果のキャッシュにサイズ制限を課します。メモリーは、FTS クエリーの処理時に必要に応じて割り当てられます。結果のキャッシュサイズ制限に達すると、クエリーで最大限に許可されるメモリー量を超えたことを示すエラーが返されます。

    MySQL 5.6.17 の時点では、すべてのプラットフォームタイプおよびプラットフォームビットサイズに対応した innodb_ft_result_cache_limit の最大値は、2**32-1 です。Bug #71554。

  • innodb_ft_server_stopword_table

    コマンド行形式--innodb-ft-server-stopword-table=db_name/table_name
    導入5.6.4
    システム変数innodb_ft_server_stopword_table
    スコープグローバル
    動的はい
    文字列
    デフォルトNULL

    このオプションは、すべての InnoDB テーブルに対応した独自の InnoDBFULLTEXT インデックスストップワードリストを指定する際に使用されます。特定の InnoDB テーブルに独自のストップワードリストを構成するには、innodb_ft_user_stopword_table を使用します。

    db_name/table_name の形式で、innodb_ft_server_stopword_table をストップワードリストを含むテーブルの名前に設定します。

    innodb_ft_server_stopword_table を構成する前に、ストップワードテーブルが存在する必要があります。FULLTEXT インデックスを作成する前に、innodb_ft_enable_stopword を有効にして、innodb_ft_server_stopword_table オプションを構成する必要あります。

    ストップワードテーブルは、VALUE という名前の単一の VARCHAR カラムを含む InnoDB テーブルにする必要があります。

    詳細は、セクション12.9.4「全文ストップワード」を参照してください。

  • innodb_ft_sort_pll_degree

    コマンド行形式--innodb-ft-sort-pll-degree=#
    導入5.6.4
    システム変数innodb_ft_sort_pll_degree
    スコープグローバル
    動的いいえ
    数値
    デフォルト2
    最小値1
    最大値32

    検索インデックスの構築時に、InnoDBFULLTEXT インデックス内のテキストのインデックス作成およびトークン化を行う際に、並列して使用されるスレッド数です。使用法の追加情報については、innodb_sort_buffer_size を参照してください。

  • innodb_ft_total_cache_size

    コマンド行形式--innodb-ft-total-cache-size=#
    導入5.6.13
    システム変数innodb_ft_total_cache_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト640000000
    最小値32000000
    最大値1600000000

    すべてのテーブルに対応した InnoDBFULLTEXT 検索インデックスキャッシュ用に割り当てられた合計メモリー量 (バイト単位) です。それぞれが全文検索インデックスを持つ多数のテーブルを作成すると、使用可能なメモリーの大部分が消費される可能性があります。innodb_ft_total_cache_size では、過剰なメモリー消費を回避する際に役立つ、すべての全文検索インデックスに対応したグローバルなメモリー制限が定義されます。インデックス操作でグローバルな制限に達すると、強制的な同期がトリガーされます。

  • innodb_ft_user_stopword_table

    コマンド行形式--innodb-ft-user-stopword-table=db_name/table_name
    導入5.6.4
    システム変数innodb_ft_user_stopword_table
    スコープグローバル、セッション
    動的はい
    文字列
    デフォルトNULL

    このオプションは、特定のテーブルに独自の InnoDBFULLTEXT インデックスストップワードリストを指定する際に使用されます。すべての InnoDB テーブル用に独自のストップワードリストを構成するには、innodb_ft_server_stopword_table を使用します。

    db_name/table_name の形式で、innodb_ft_user_stopword_table をストップワードリストを含むテーブルの名前に設定します。

    innodb_ft_user_stopword_table を構成する前に、ストップワードテーブルが存在する必要があります。FULLTEXT インデックスを作成する前に、innodb_ft_enable_stopword を有効にして、innodb_ft_user_stopword_table オプションを構成する必要あります。

    ストップワードテーブルは、VALUE という名前の単一の VARCHAR カラムを含む InnoDB テーブルにする必要があります。

    詳細は、セクション12.9.4「全文ストップワード」を参照してください。

  • innodb_io_capacity

    コマンド行形式--innodb-io-capacity=#
    システム変数innodb_io_capacity
    スコープグローバル
    動的はい
    数値
    デフォルト200
    最小値100
    最大値 (64 ビットプラットフォーム)2**64-1
    最大値 (32 ビットプラットフォーム)2**32-1

    innodb_io_capacity パラメータは、InnoDB バックグラウンドタスクで実行される I/O アクティビティー (バッファープールからのページのフラッシュ挿入バッファーからのデータのマージなど) に上限を設定します。デフォルト値は 200 です。高い I/O レートを処理できる高負荷のシステムでは、サーバーの起動時に大きい値を設定すると、サーバーが高いレートの行変更に関連付けられたバックグラウンドメンテナンス作業を処理できるようになります。

    innodb_io_capacity の制限は、すべてのバッファープールインスタンスに対する合計の制限です。ダーティーページがフラッシュされるとき、innodb_io_capacity 制限は、バッファープールインスタンス間で均等に分割されます。

    個別の 5400 RPM または 7200 RPM ドライブが搭載されたシステムでは、元のデフォルトの 100 まで値を小さくするとよいでしょう。

    このパラメータはほぼ、システムが 1 秒あたりに実行できる I/O 操作の数に設定するようにしてください。理想的には、この設定はできるだけ小さく保ちます。ただし、これらのバックグラウンドアクティビティーに遅延が発生するほど小さくしないでください。値が大きすぎる場合は、データがバッファープールおよび挿入バッファーから瞬時に削除されるため、キャッシュを使用する重要な利点が得られません。

    この値は、約 100 IOPS を実行できる旧世代のディスクドライブで実現可能な IOPS (I/O Operations Per Second) の推定比率を表します。現在のデフォルトの 200 は、最新のストレージデバイスがさらに高い I/O レートを処理できることを反映しています。

    一般に、InnoDB の I/O で使用されるドライブ (特に、高い数値の IOPS を処理できる高速ドライブ) の数に応じて、値を大きくすることができます。たとえば、InnoDB 用に複数のディスクまたはソリッドステートディスクを使用するシステムでは、このパラメータを制御する機能の利点が得られる可能性が高くなります。

    非常に大きい数値も指定できますが、実際にはこのような大きな値にすると、利点を得られるとしてもわずかです。たとえば、100 万は非常に大きい値と考えられます。

    innodb_io_capacity の値は、innodb_io_capacity_max で定義された最大値まで、100 以上の任意の数値に設定できます。デフォルト値は 200 です。このパラメータの値は MySQL オプションファイル (my.cnf または my.ini) で設定するか、あるいは SET GLOBAL コマンド (これには SUPER 権限が必要です) で動的に変更できます。

    このオプションに関する詳細なガイドラインについては、セクション14.13.8「InnoDB マスタースレッドの I/O レートの構成」を参照してください。InnoDB の I/O パフォーマンスに関する一般的な情報については、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_io_capacity_max

    コマンド行形式--innodb-io-capacity-max=#
    導入5.6.6
    システム変数innodb_io_capacity_max
    スコープグローバル
    動的はい
    数値
    デフォルト (Windows, 64 ビットプラットフォーム)2000
    デフォルト (Unix, 64 ビットプラットフォーム)see description
    デフォルト (32 ビットプラットフォーム)see description
    最小値2000
    最大値 (Windows, 64 ビットプラットフォーム)2**32-1
    最大値 (Unix, 64 ビットプラットフォーム)2**64-1
    最大値 (32 ビットプラットフォーム)2**32-1

    緊急時に innodb_io_capacity の設定を拡張する際に、InnoDB で許可されている上限です。起動時に innodb_io_capacity の設定を指定し、innodb_io_capacity_max に値を指定しない場合は、innodb_io_capacity_max のデフォルト値が innodb_io_capacity の 2 倍となり、下限が 2000 となります。また、2000 は初期のデフォルト innodb_io_capacity_max 構成値です。

    innodb_io_capacity_max 設定は、すべてのバッファープールインスタンスに対する合計の制限です。

    MySQL 5.6 開発中の短期間は、この変数は innodb_max_io_capacity と呼ばれていました。MySQL 5.6.7 では、innodb_io_capacity オプションとの関係を強調するために、innodb_io_capacity_max という名前に変更されました。

  • innodb_large_prefix

    コマンド行形式--innodb-large-prefix
    導入5.6.3
    システム変数innodb_large_prefix
    スコープグローバル
    動的はい
    ブール
    デフォルトOFF

    このオプションを有効にすると、DYNAMIC および COMPRESSED 行フォーマットを使用する InnoDB テーブルで、767 バイトよりも長い (最大で 3072 バイトの) インデックスキープリフィクスが許可されます。(このようなテーブルの作成には、innodb_file_format=barracuda および innodb_file_per_table=true のオプション値も必要になります。)さまざまな設定でインデックスキープリフィクスに関連付けられた関連性の最大値については、セクション14.6.7「InnoDB テーブル上の制限」を参照してください。

    REDUNDANT および COMPACT 行フォーマットを使用したテーブルでは、このオプションによってキープリフィクスの長さは影響を受けません。

  • innodb_lock_wait_timeout

    コマンド行形式--innodb-lock-wait-timeout=#
    システム変数innodb_lock_wait_timeout
    スコープグローバル、セッション
    動的はい
    数値
    デフォルト50
    最小値1
    最大値1073741824

    行ロックが解除されるまで InnoDBトランザクションが待機する時間の長さ (秒単位) です。デフォルト値は 50 秒です。別の InnoDB トランザクションでロックされている行へのアクセスを試みるトランザクションは、行への書き込みアクセスを最大でこの秒数間待機してから、次のエラーを発行します。

    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

    ロック待機のタイムアウトが発生すると、(トランザクション全体ではなく) 現在のステートメントがロールバックされます。トランザクション全体をロールバックするには、--innodb_rollback_on_timeout オプションを付けてサーバーを起動します。セクション14.19.4「InnoDB のエラー処理」も参照してください。

    高度にインタラクティブなアプリケーションまたは OLTP システムでは、ユーザーのフィードバックをすばやく表示したり、あとで処理するために更新をキューに入れたりするために、この値を小さくするとよいでしょう。長時間実行されるバックエンド操作 (その他の大規模な挿入操作や更新操作が完了するまで待機するデータウェアハウスでの変換ステップなど) では、この値を大きくするとよいでしょう。

    innodb_lock_wait_timeoutInnoDB の行ロックにのみ適用されます。MySQL のテーブルロックInnoDB 内部では発生せず、このタイムアウトはテーブルロックの待機には適用されません。

    デッドロックInnoDB によってすぐに検出され、デッドロックになったトランザクションのいずれかがロールバックされるため、デッドロックにはロック待機のタイムアウト値が適用されません。

    innodb_lock_wait_timeout は、実行時に SET GLOBAL または SET SESSION ステートメントとともに設定できます。GLOBAL 値を変更するには、SUPER 権限が必要です。これを変更すると、それ以降に接続するすべてのクライアントの操作が影響を受けます。任意のクライアントが innodb_lock_wait_timeoutSESSION 設定を変更でき、そのクライアントのみが影響を受けます。

  • innodb_locks_unsafe_for_binlog

    コマンド行形式--innodb-locks-unsafe-for-binlog
    非推奨5.6.3
    システム変数innodb_locks_unsafe_for_binlog
    スコープグローバル
    動的いいえ
    ブール
    デフォルトOFF

    この変数によって、InnoDB が検索およびインデックススキャンでギャップロックを使用する方法が影響を受けます。MySQL 5.6.3 の時点では、innodb_locks_unsafe_for_binlog は非推奨となり、今後の MySQL リリースで削除される予定です。

    通常、InnoDB では、インデックス行ロックとギャップロックを組み合わせた「ネクストキーロック」と呼ばれるアルゴリズムが使用されます。InnoDB は、テーブルインデックスを検索またはスキャンするときに、生成されたインデックスレコード上に共有ロックまたは排他ロックを設定するという方法で、行レベルロックを実行します。したがって、行レベルロックは、実際にはインデックスレコードロックです。さらに、あるインデックスレコードに対するネクストキーロックによって、そのインデックスレコードの前のギャップも影響を受けます。つまり、ネクストキーロックは、インデックスレコードロックと、そのインデックスレコードの前のギャップに対するギャップロックとを組み合わせたものです。あるセッションがインデックス内のレコード R 上に共有ロックまたは排他ロックを持っている場合は、別のセッションがインデックスの順番で R の直前にあるギャップに新しいインデックスレコードを挿入できません。セクション14.2.6「InnoDB のレコード、ギャップ、およびネクストキーロック」を参照してください。

    innodb_locks_unsafe_for_binlog の値はデフォルトで 0 (無効) になっていますが、これは、ギャップロックが有効であることを意味します。InnoDB はネクストキーロックを使用して、検索およびインデックススキャンを実行します。この変数を有効にするには、値を 1 に設定します。これにより、ギャップロックが無効になります。InnoDB はインデックスレコードロックのみを使用して、検索およびインデックススキャンを実行します。

    innodb_locks_unsafe_for_binlog を有効にしても、外部キー制約チェックや重複キーチェックでのギャップロックの使用は無効になりません。

    innodb_locks_unsafe_for_binlog を有効にした場合の影響は、トランザクション分離レベルを READ COMMITTED に設定した場合の影響に似ていますが、同じではありません。

    • innodb_locks_unsafe_for_binlog を有効にすることはグローバルな設定であるため、すべてのセッションが影響を受けます。その一方で、分離レベルは、すべてのセッションに対してグローバルに設定することも、セッションごとに個別に設定することもできます。

    • innodb_locks_unsafe_for_binlog はサーバー起動時にしか設定できないのに対して、分離レベルは起動時に設定することも、実行時に変更することもできます。

    したがって、READ COMMITTED では innodb_locks_unsafe_for_binlog よりも細かく柔軟な制御が提供されます。ギャップロックに対する分離レベルの影響に関する追加の詳細については、セクション13.3.6「SET TRANSACTION 構文」を参照してください。

    ギャップロックが無効になるとほかのセッションが新しい行をギャップに挿入できるため、innodb_locks_unsafe_for_binlog を有効にすると、ファントムの問題が発生する可能性があります。child テーブルの id カラム上にインデックスがあり、識別子の値が 100 よりも大きいすべての行をテーブルから読み取り、選択された行の一部のカラムをあとで更新するという意図でロックすると仮定します。

    SELECT * FROM child WHERE id > 100 FOR UPDATE;

    クエリーでは、id が 100 より大きい最初のレコードからインデックスがスキャンされます。その範囲内のインデックスレコード上に設定されたロックによって、ギャップへの挿入がロックアウトされていない場合は、別のセッションがそのテーブルに新しい行を挿入できます。したがって、同じトランザクション内で同じ SELECT を再度実行すると、クエリーから返された結果セット内に新しい行を見つけることができます。これは、データベースに新しい項目が追加された場合は、InnoDB で直列化可能性が保証されないことも意味します。したがって、innodb_locks_unsafe_for_binlog が有効な場合に InnoDB によって保証される最大の分離レベルは、READ COMMITTED になります。(競合直列化可能性は引き続き保証されます。)ファントムの追加情報については、セクション14.2.7「ネクストキーロックによるファントム問題の回避」を参照してください。

    innodb_locks_unsafe_for_binlog を有効にした場合には、次のような影響も発生します。

    • UPDATE または DELETE ステートメントでは、InnoDB は更新または削除の対象となる行に対してのみ、ロックを保持します。一致しなかった行のレコードロックは、MySQL による WHERE 条件の評価後に解除されます。これにより、デッドロックの可能性が大幅に低くなりますが、まだ発生する可能性はあります。

    • UPDATE ステートメントである行がすでにロックされていた場合、InnoDB半一貫性 読み取りを実行し、最後にコミットされたバージョンを MySQL に返すため、MySQL はその行が UPDATEWHERE 条件に一致するかどうかを判断できます。その行が一致した場合 (その行を更新する必要がある場合)、MySQL はその行を再度読み取り、InnoDB は今度はその行をロックするか、その行のロックが解除されるまで待機します。

    次のような例について、このテーブルから検討します。

    CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
    INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
    COMMIT;

    この場合は、テーブルにインデックスが設定されていないため、検索およびインデックススキャンでは、非表示のクラスタ化されたインデックスを使用してレコードのロックが行われます (セクション14.2.13.2「クラスタインデックスとセカンダリインデックス」を参照してください)。

    あるクライアントが次のステートメントを使用して、UPDATE を実行すると仮定します。

    SET autocommit = 0;
    UPDATE t SET b = 5 WHERE b = 3;

    また、2 番目のクライアントが 1 番目のクライアントの実行後に次のステートメントを実行することで、UPDATE を実行すると仮定します。

    SET autocommit = 0;
    UPDATE t SET b = 4 WHERE b = 2;

    InnoDB は各 UPDATE を実行する際に、まず各行の排他ロックを取得し、次にその行を変更するかどうかを判断します。InnoDB がその行を変更せず、かつ innodb_locks_unsafe_for_binlog が有効な場合は、そのロックが解除されます。それ以外の場合、トランザクションが終了するまで InnoDB はそのロックを保持します。これにより、トランザクション処理が次のような影響を受けます。

    innodb_locks_unsafe_for_binlog が無効な場合は次のように、最初の UPDATE は X ロックを取得し、そのいずれも解除しません。

    x-lock(1,2); retain x-lock
    x-lock(2,3); update(2,3) to (2,5); retain x-lock
    x-lock(3,2); retain x-lock
    x-lock(4,3); update(4,3) to (4,5); retain x-lock
    x-lock(5,2); retain x-lock

    次のように、2 番目の UPDATE は (1 番目の更新がすべての行のロックを保持しているため)、ロックを取得しようとしてもすぐにブロックされ、1 番目の UPDATE がコミットまたはロールバックを実行するまで続行されません。

    x-lock(1,2); block and wait for first UPDATE to commit or roll back

    innodb_locks_unsafe_for_binlog が有効な場合は次のように、最初の UPDATE は X ロックを取得したあとに、変更されない行のロックを解除します。

    x-lock(1,2); unlock(1,2)
    x-lock(2,3); update(2,3) to (2,5); retain x-lock
    x-lock(3,2); unlock(3,2)
    x-lock(4,3); update(4,3) to (4,5); retain x-lock
    x-lock(5,2); unlock(5,2)

    2 番目の UPDATE では次のように、InnoDB半一貫性 読み取りを行い、最後にコミットされたバージョンを MySQL に返すため、MySQL はその行が UPDATEWHERE 条件に一致するかどうかを判断できます。

    x-lock(1,2); update(1,2) to (1,4); retain x-lock
    x-lock(2,3); unlock(2,3)
    x-lock(3,2); update(3,2) to (3,4); retain x-lock
    x-lock(4,3); unlock(4,3)
    x-lock(5,2); update(5,2) to (5,4); retain x-lock
  • innodb_log_buffer_size

    コマンド行形式--innodb-log-buffer-size=#
    システム変数innodb_log_buffer_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト8388608
    最小値262144
    最大値4294967295

    ディスク上のログファイルに書き込む際に InnoDB で使用されるバッファーのサイズ (バイト単位) です。デフォルトの値は 8M バイトです。ログバッファーを大きくすると、トランザクションがコミットする前にディスクにログを書き込まなくても、大規模なトランザクションを実行できます。したがって、多数の行を更新、挿入、または削除するトランザクションの場合、ログバッファーを大きくすると、ディスク I/O を節約できます。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_log_compressed_pages

    コマンド行形式--innodb-log-compressed-pages=#
    導入5.6.11
    システム変数innodb_log_compressed_pages
    スコープグローバル
    動的はい
    ブール
    デフォルトON

    再圧縮されたページのイメージが InnoDBRedo ログに格納されるかどうかを指定します。

    この変数は MySQL 5.6.11 で追加されました。

  • innodb_log_file_size

    コマンド行形式--innodb-log-file-size=#
    システム変数innodb_log_file_size
    スコープグローバル
    動的いいえ
    数値
    デフォルト (≥ 5.6.8)50331648
    デフォルト (≤ 5.6.7)5242880
    最小値1048576
    最大値 (≥ 5.6.3)512GB / innodb_log_files_in_group
    最大値 (≤ 5.6.2)4GB / innodb_log_files_in_group

    ロググループ内の各ログファイルのサイズ (バイト単位) です。ログファイルを結合したサイズ (innodb_log_file_size * innodb_log_files_in_group) は、512G バイトよりもわずかに小さい最大値を上回ることができません。たとえば、255G バイトのログファイルのペアを使用すれば、制限に近づくことはできますが、上回ることはできません。デフォルト値は 48M バイトです。適切な値の範囲は、1M バイトから 1/バッファープールN 番目のサイズまでです。ここで、N はグループ内のログファイルの数です。値を大きくするほど、バッファープール内で必要となるチェックポイントフラッシュアクティビティーの数が少なくなるため、ディスク I/O を節約できます。また、ログファイルを大きくすると、クラッシュリカバリの速度が遅くなります。ただし、MySQL 5.5 以上ではリカバリのパフォーマンスが改善されているため、ログファイルのサイズに対する考慮事項も少なくなります。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

    重要

    Bug #69477 が原因で、外部に格納された大きな BLOB フィールドに対する Redo ログの書き込みによって、最新のチェックポイントが上書きされる可能性があります。このバグに対処するために MySQL 5.6.20 で導入されたパッチを適用すれば、BLOB で書き込まれる Redo ログのサイズが Redo ログファイルサイズの 10% に制限されます。この制限の結果として、innodb_log_file_size は、テーブルの行で見つかった最大の BLOB データサイズの 10 倍よりも大きい値に、その他の変数の長さフィールド (VARCHARVARBINARY、および TEXT 型のフィールド) の長さを加えた値に設定されるはずです。

    MySQL 5.6.22 では、Redo ログ BLOB の書き込み制限は 合計 Redo ログサイズ (innodb_log_file_size * innodb_log_files_in_group) の 10% に緩められました。(Bug #19498877)

  • innodb_log_files_in_group

    コマンド行形式--innodb-log-files-in-group=#
    システム変数innodb_log_files_in_group
    スコープグローバル
    動的いいえ
    数値
    デフォルト2
    最小値2
    最大値100

    ロググループ内のログファイルの数です。InnoDB はファイルに輪状に書き込みをします。デフォルト (推奨) 値は 2 です。これらのファイルの場所は、innodb_log_group_home_dir で指定されます。ログファイルを結合したサイズ (innodb_log_file_size * innodb_log_files_in_group) は、最大で 512G バイトにすることができます。

  • innodb_log_group_home_dir

    コマンド行形式--innodb-log-group-home-dir=path
    システム変数innodb_log_group_home_dir
    スコープグローバル
    動的いいえ
    ディレクトリ名

    InnoDBRedo ログファイルへのディレクトリパスです。この数は、innodb_log_files_in_group で指定されます。どの InnoDB ログ変数も指定しない場合は、デフォルトで、MySQL データディレクトリ内に ib_logfile0 および ib_logfile1 という名前の 2 つのファイルが作成されます。これらのサイズは、innodb_log_file_size システム変数のサイズで指定されます。

  • innodb_lru_scan_depth

    コマンド行形式--innodb-lru-scan-depth=#
    導入5.6.3
    システム変数innodb_lru_scan_depth
    スコープグローバル
    動的はい
    数値
    デフォルト1024
    最小値100
    最大値 (64 ビットプラットフォーム)2**64-1
    最大値 (32 ビットプラットフォーム)2**32-1

    InnoDBバッファープールでのフラッシュ操作のアルゴリズムおよびヒューリスティクスに影響を与えるパラメータです。主に、I/O インテンシブなワークロードを調整するパフォーマンスの専門家が関心を持つものです。バッファープールインスタンスごとに、page_cleaner スレッドがフラッシュするダーティーページを検索する際に、どのくらいの深さまでバッファープール LRU リストをスキャンするのかが指定されます。これは、1 秒ごとに 1 回実行されるバックグラウンド操作です。一般的なワークロードで予備の I/O 容量を持っている場合は、この値を大きくします。書き込みが集中するワークロードで I/O 容量がいっぱいになった場合は、この値を小さくします (特に大きなバッファープールを持っている場合)。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_max_dirty_pages_pct

    コマンド行形式--innodb-max-dirty-pages-pct=#
    システム変数innodb_max_dirty_pages_pct
    スコープグローバル
    動的はい
    数値
    デフォルト75
    最小値0
    最大値99

    InnoDB は、ダーティーページの割合がこの値を超えないように、バッファープールからデータをフラッシュしようと試みます。0 から 99 までの範囲内の整数を指定します。デフォルト値は 75 です。

    innodb_max_dirty_pages_pct 設定は、フラッシュアクティビティーのターゲットを確立します。フラッシュの頻度には影響を与えません。フラッシュの頻度の管理については、セクション14.13.1.2「InnoDB バッファープールのフラッシュの頻度の構成」を参照してください。

    この変数に関する追加情報については、セクション14.13.1.6「InnoDB バッファープールのフラッシュのチューニング」を参照してください。一般的な I/O チューニングのアドバイスについては、セクション8.5.7「InnoDB ディスク I/O の最適化」を参照してください。

  • innodb_max_dirty_pages_pct_lwm

    コマンド行形式--innodb-max-dirty-pages-pct-lwm=#
    導入5.6.6
    システム変数innodb_max_dirty_pages_pct_lwm
    スコープグローバル
    動的はい
    数値
    デフォルト0
    最小値0
    最大値99

    ダーティーページの比率を制御するために事前フラッシュが有効になっている場合に、ダーティーページの割合を表す低位境界値です。デフォルトの 0 では、事前フラッシュの動作が完全に無効になります。この変数に関する追加情報については、セクション14.13.1.6「InnoDB バッファープールのフラッシュのチューニング」を参照してください。

  • innodb_max_purge_lag

    コマンド行形式--innodb-max-purge-lag=#
    システム変数innodb_max_purge_lag
    スコープグローバル
    動的はい
    数値
    デフォルト0
    最小値0
    最大値4294967295

    この変数は、パージ操作が遅れたときに、INSERTUPDATE、および DELETE 操作を遅延させる方法を制御します (セクション14.2.12「InnoDB マルチバージョン」を参照してください)。デフォルト値は 0 (遅延なし) です。

    InnoDB トランザクションシステムでは、UPDATE または DELETE 操作で削除のマークが付けられたインデックスレコードを含むトランザクションのリストが保持されます。purge_lag の値は、このリストの長さを表しています。purge_laginnodb_max_purge_lag を超えると、各 INSERTUPDATE、および DELETE 操作が遅延します。

    purge_lag が非常に大きくなるような極端な状況で、過剰な遅延を回避するには、innodb_max_purge_lag_delay 構成オプションを設定すれば、遅延の量