MySQL 8.0 リファレンスマニュアル


16.3 MEMORY ストレージエンジン

MEMORY ストレージエンジン (従来は HEAP と呼ばれていました) は、メモリーに格納された内容で特定用途のテーブルを作成します。 データは、クラッシュ、ハードウェア問題、または電源停止に弱いため、これらのテーブルは、一時的な作業領域またはほかのテーブルから抽出されたデータの読み取り専用キャッシュとして使用されるだけです。

表 16.4 「MEMORY ストレージエンジンの機能」

機能 Support
B ツリーインデックス はい
MVCC いいえ
T ツリーインデックス いいえ
インデックスキャッシュ N/A
クラスタデータベースのサポート いいえ
クラスタ化されたインデックス いいえ
ストレージの制限 RAM
データキャッシュ N/A
データディクショナリ向け更新統計 はい
トランザクション いいえ
ハッシュインデックス はい
バックアップ/ポイントインタイムリカバリ (ストレージエンジン内ではなくサーバー内で実装されています。) はい
レプリケーションのサポート (ストレージエンジン内ではなくサーバー内で実装されています。) 制限付き (このセクションの後半の説明を参照してください。)
ロック粒度 Table
全文検索インデックス いいえ
圧縮データ いいえ
地理空間インデックスのサポート いいえ
地理空間データ型のサポート いいえ
外部キーのサポート いいえ
暗号化データ はい (暗号化機能を介してサーバーに実装されます。)

MEMORY または NDB Cluster を使用する場合

重要で可用性の高い、または頻繁に更新されるデータのために MEMORY ストレージエンジンを使用するアプリケーションを配備する開発者は、NDB Cluster の方がよいかどうかを考慮するようにしてください。 MEMORY エンジンの典型的なユースケースには、次の特徴があります。

  • セッション管理やキャッシングなどの一時的で重要でないデータに関連する操作。 MySQL サーバーが停止または再起動したときに、MEMORY テーブルのデータは失われます。

  • 高速アクセスおよび低待機時間のためのインメモリー保存。 データボリュームはメモリー内に完全に収まり、オペレーティングシステムによる仮想メモリーページのスワップアウトはありません。

  • 読み取り専用または読み取りが大半のデータのアクセスパターン (更新が制限されています)。

NDB Cluster は、より高いパフォーマンスレベルの MEMORY エンジンと同じ機能を提供し、MEMORY では使用できない追加機能を提供します:

  • クライアント間で競合の少ない行レベルロックとマルチスレッド操作。

  • 書き込みを含むステートメント混在時の拡張性。

  • データ持続性のためのディスクバックアップ式操作 (オプション)。

  • 単一障害点がない、シェアードナッシングアーキテクチャーと複数ホスト操作。99.999% の可用性を実現できます。

  • ノードをまたがる自動データ分散。アプリケーションの開発者はカスタムの共有またはパーティション化ソリューションを作る必要がありません。

  • 可変長データ型 (MEMORY がサポートしない BLOB および TEXT を含みます) をサポートします。

パーティション化

MEMORY テーブルはパーティション化できません。

パフォーマンスの特徴

MEMORY のパフォーマンスは、更新処理時のシングルスレッド実行とテーブルロックオーバーヘッドが原因の競合によって抑制されます。 このため、負荷が増えたときに拡張性が制限されます (特に、書き込みを含むステートメント混在時)。

MEMORY テーブルのインメモリー処理にかかわらず、それらは、汎用目的クエリーのために、または読み取り/書き込み負荷では、必ずしもビジーサーバーの InnoDB テーブルより高速である必要はありません。 特に、更新実行に関与するテーブルロックは、複数セッションからの MEMORY テーブルの並列使用の速度を低下させる可能性があります。

MEMORY テーブルで実行されるクエリーの種類によっては、デフォルトのハッシュデータ構造 (一意キーで 1 つの値を検索する場合)、または汎用目的の B ツリーデータ構造 (等号、不等号、未満または「- を超える」などの範囲演算子などを含むすべての種類のクエリーの場合) のいずれかとしてインデックスを作成する場合があります。 次のセクションでは、両方の種類のインデックスを作成するための構文について説明します。 パフォーマンス面でよくある問題は、B ツリーインデックスがより効率的な作業負荷で、デフォルトのハッシュインデックスを使用していることです。

MEMORY テーブルの特性

MEMORY ストレージエンジンは、ディスク上にファイルを作成しません。 テーブル定義は、MySQL データディクショナリに格納されます。

MEMORY テーブルには次のような特徴があります。

  • MEMORY テーブルの領域は小さなブロックに割り当てられます。 テーブルは、挿入に 100% 動的ハッシュを使用します。 オーバーフロー領域や余分なキー領域は必要ありません。 フリーリスト用の余分な領域は必要ありません。 削除された行はリンクリストに置かれ、新しいデータをテーブルに挿入するときに再利用されます。 MEMORY テーブルでは、ハッシュテーブルで一般的に削除 + 挿入に関連付けられる問題も起こりません。

  • MEMORY テーブルは固定長の行ストレージフォーマットを使用します。 VARCHAR などの可変長型は、固定長を使用して格納されます。

  • MEMORY テーブルは BLOB または TEXT カラムを含むことができません。

  • MEMORYAUTO_INCREMENT カラムのサポートを含みます。

  • TEMPORARY MEMORY でないテーブルは、ほかの TEMPORARY でないテーブルと同様に、すべてのクライアントで共有されます。

MEMORY テーブルへの DDL 操作

MEMORY テーブルを作成するには、CREATE TABLE ステートメントで ENGINE=MEMORY 句を指定します。

CREATE TABLE t (i INT) ENGINE = MEMORY;

エンジンの名前が表すように、MEMORY テーブルはメモリーに格納されます。 デフォルトではハッシュインデックスを使用するため、単一値の検索には非常に高速であり、一時テーブルの作成には非常に役立ちます。 ただし、サーバーがシャットダウンすると、MEMORY テーブルに格納されたすべての行が失われます。 定義は MySQL データディクショナリに格納されますが、サーバーの再起動時には空であるため、テーブル自体は引き続き存在します。

この例は、MEMORY テーブルをどのように作成、使用、および削除できるかを示しています。

mysql> CREATE TABLE test ENGINE=MEMORY
           SELECT ip,SUM(downloads) AS down
           FROM log_table GROUP BY ip;
mysql> SELECT COUNT(ip),AVG(down) FROM test;
mysql> DROP TABLE test;

MEMORY テーブルの最大サイズは max_heap_table_size システム変数によって制限されます (デフォルト値は 16M バイト)。 MEMORY テーブルに異なるサイズ制限を適用するには、この変数値を変更します。 CREATE TABLE、それに続く ALTER TABLE または TRUNCATE TABLE の実質的な値は、テーブルの有効期限に使用される値です。 サーバーを再起動しても、既存の MEMORY テーブルの最大サイズがグローバルの max_heap_table_size 値に設定されます。 各テーブルのサイズをこのセクションの後半で説明するように設定できます。

インデックス

MEMORY ストレージエンジンは HASHBTREE の両方のインデックスをサポートしています。 ここに示すように USING 句を追加することによりどちらであるかを指定できます。

CREATE TABLE lookup
    (id INT, INDEX USING HASH (id))
    ENGINE = MEMORY;
CREATE TABLE lookup
    (id INT, INDEX USING BTREE (id))
    ENGINE = MEMORY;

B ツリーとハッシュインデックスの一般的な特徴については、セクション8.3.1「MySQL のインデックスの使用の仕組み」を参照してください。

MEMORY テーブルでは、テーブル当たり最大で 64 個のインデックス、インデックス当たり 16 個のカラム、3072 バイトの最大キー長を持つことができます。

MEMORY テーブルのハッシュインデックスでキーの重複の程度が高いと (同じ値を含むインデックスエントリが多い)、キー値に影響を与えるテーブルへの更新処理とすべての削除処理の速度が大きく低下します。 この低下の程度は重複の程度に比例します (または、インデックスカーディナリティーに反比例します)。 BTREE インデックスを使用することで、この問題を回避できます。

MEMORY テーブルには、非一意キーを持つことができます。 (これは、ハッシュインデックスの実装ではまれな特徴です。)

インデックスが付けられたカラムに NULL 値を含むことができます。

ユーザー作成の一時テーブル

MEMORY テーブルの内容はメモリーに格納されます。これは MEMORY テーブルが、クエリーの処理中にその場でサーバーが作成する内部一時テーブルと共有する特性です。 ただし、2 つのタイプのテーブルには違いがあり、MEMORY テーブルはストレージ変換の影響を受けませんが、内部一時テーブルは次のような影響があります。

データのロード

MySQL サーバーの起動時に MEMORY テーブルに移入するには、init_file システム変数を使用できます。 たとえば、INSERT INTO ... SELECTLOAD DATA などのステートメントをファイルに挿入して永続データソースからテーブルをロードし、init_file を使用してファイルに名前を付けることができます。 セクション5.1.8「サーバーシステム変数」およびセクション13.2.7「LOAD DATA ステートメント」を参照してください。

MEMORY テーブルとレプリケーション

レプリケーションソースサーバーが停止して再起動すると、その MEMORY テーブルは空になります。 この効果をレプリカにレプリケートするには、ソースが起動後に最初に特定の MEMORY テーブルを使用するときに、そのテーブルの DELETE ステートメントまたは (MySQL 8.0.22 から) TRUNCATE TABLE ステートメントをバイナリログに書き込むことによってテーブルを空にする必要があることをレプリカに通知するイベントをログに記録します。 レプリカサーバーを停止して再起動すると、その MEMORY テーブルも空になり、DELETE または (MySQL 8.0.22 から) TRUNCATE TABLE ステートメントが独自のバイナリログに書き込まれ、ダウンストリームレプリカに渡されます。

レプリケーショントポロジで MEMORY テーブルを使用する場合、状況によっては、ソースのテーブルとレプリカのテーブルが異なることがあります。 失効した読取りまたはエラーを防ぐためのこれらの各状況の処理の詳細は、セクション17.5.1.21「レプリケーションと MEMORY テーブル」 を参照してください。

メモリー使用量の管理

サーバーには、同時に使用されるすべての MEMORY テーブルを保持するための十分なメモリーが必要です。

MEMORY テーブルから各行を削除しても、メモリーは再利用されません。 テーブル全体が削除された場合にのみ、メモリーが再利用されます。 削除された行に以前に使用されたメモリーは同じテーブル内の新しい行に再利用されます。 MEMORY テーブルの内容が必要でなくなったときに、それが使用していたすべてのメモリーを解放するには、DELETE または TRUNCATE TABLE を実行してすべての行を削除するか、DROP TABLE を使用してテーブルを完全に削除します。 削除された行が使用していたメモリーを解放するには、ALTER TABLE ENGINE=MEMORY を使用してテーブルを強制的に再作成します。

MEMORY テーブルで 1 つの行に必要なメモリーは、次の式で計算されます。

SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) * 4)
+ SUM_OVER_ALL_HASH_KEYS(sizeof(char*) * 2)
+ ALIGN(length_of_row+1, sizeof(char*))

ALIGN() は行の長さを char ポインタサイズのちょうど倍数にするための切り上げ係数を表します。sizeof(char*) は 32 ビットマシンでは 4、64 ビットマシンでは 8 です。

前に述べたように、max_heap_table_size システム変数は MEMORY テーブルの最大サイズの制限値を設定します。 各テーブルの最大サイズを制御するには、各テーブルを作成する前に、この変数のセッション値を設定します。 (すべてのクライアントが作成した MEMORY テーブルに、グローバル max_heap_table_size 値を使用するのでなければ、この値を変更しないでください。) 次は、2 つの MEMORY テーブル (最大サイズがそれぞれ 1M バイトと 2M バイト) を作成する例です。

mysql> SET max_heap_table_size = 1024*1024;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t1 (id INT, UNIQUE(id)) ENGINE = MEMORY;
Query OK, 0 rows affected (0.01 sec)

mysql> SET max_heap_table_size = 1024*1024*2;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t2 (id INT, UNIQUE(id)) ENGINE = MEMORY;
Query OK, 0 rows affected (0.00 sec)

両方のテーブルは、サーバーが再起動した場合、サーバーのグローバル max_heap_table_size 値に戻ります。

MEMORY テーブルに対して CREATE TABLE ステートメントの MAX_ROWS テーブルオプションを指定して、テーブルに格納する予定の行数に関するヒントを提供することもできます。 これによって max_heap_table_size 値 (引き続き最大テーブルサイズの制約として機能) を超えてテーブルが拡大できなくなります。 MAX_ROWS を使用できるだけの最大限の柔軟性を得るには、少なくとも各 MEMORY テーブルが拡大できる値程度に max_heap_table_size を設定してください。

追加のリソース

MEMORY ストレージエンジンに特化したフォーラムは、https://forums.mysql.com/list.php?92で参照できます。


関連キーワード:  テーブル, MEMORY, ストレージ, エンジン, インデックス, サーバー, 作成, TABLE, メモリー, データ