MEMORY
ストレージエンジン (従来は HEAP
と呼ばれていました) は、メモリーに格納された内容で特定用途のテーブルを作成します。データは、クラッシュ、ハードウェア問題、または電源停止に弱いため、これらのテーブルは、一時的な作業領域またはほかのテーブルから抽出されたデータの読み取り専用キャッシュとして使用されるだけです。
表 15.4 MEMORY ストレージエンジンの機能
機能 | Support |
---|---|
B ツリーインデックス | はい |
MVCC | いいえ |
T ツリーインデックス | いいえ |
インデックスキャッシュ | N/A |
クエリーキャッシュのサポート | はい |
クラスタデータベースのサポート | いいえ |
クラスタ化されたインデックス | いいえ |
ストレージの制限 | RAM |
データキャッシュ | N/A |
データディクショナリ向け更新統計 | はい |
トランザクション | いいえ |
ハッシュインデックス | はい |
バックアップ/ポイントインタイムリカバリ (ストレージエンジン内ではなくサーバー内で実装されています。) | はい |
レプリケーションのサポート (ストレージエンジン内ではなくサーバー内で実装されています。) | はい |
ロック粒度 | テーブル |
全文検索インデックス | いいえ |
圧縮データ | いいえ |
地理空間インデックスのサポート | いいえ |
地理空間データ型のサポート | いいえ |
外部キーのサポート | いいえ |
暗号化データ (ストレージエンジン内ではなくサーバー内で (暗号化関数を使って) 実装されています。) | はい |
MEMORY または MySQL Cluster を使用する場合
重要で更新頻度の高い高可用性のデータに対して MEMORY
ストレージエンジンを使用するアプリケーションを配備しようとする開発者は、MySQL Cluster がより良い選択かどうかを検討するはずです。MEMORY
エンジンの典型的なユースケースには、次の特徴があります。
セッション管理やキャッシングなどの一時的で重要でないデータに関連する操作。MySQL サーバーが停止または再起動したときに、
MEMORY
テーブルのデータは失われます。高速アクセスおよび低待機時間のためのインメモリー保存。データボリュームはメモリー内に完全に収まり、オペレーティングシステムによる仮想メモリーページのスワップアウトはありません。
読み取り専用または読み取りが大半のデータのアクセスパターン (更新が制限されています)。
MySQL Cluster は、MEMORY
エンジンと同じ機能をより高いパフォーマンスレベルで提供し、MEMORY
で利用できない追加機能を提供します。
クライアント間で競合の少ない行レベルロックとマルチスレッド操作。
書き込みを含むステートメント混在時の拡張性。
データ持続性のためのディスクバックアップ式操作 (オプション)。
単一障害点がない、シェアードナッシングアーキテクチャーと複数ホスト操作。99.999% の可用性を実現できます。
ノードをまたがる自動データ分散。アプリケーションの開発者はカスタムの共有またはパーティション化ソリューションを作る必要がありません。
可変長データ型 (
MEMORY
がサポートしないBLOB
およびTEXT
を含みます) をサポートします。
MEMORY
ストレージエンジンと MySQL Cluster の詳細な比較に関するホワイトペーパーについては、MySQL Cluster による Web サービスの拡張: MySQL Memory ストレージエンジンの代替を参照してください。このホワイトペーパーには、2 つの技術のパフォーマンス調査と、既存の MEMORY
ユーザーが MySQL Cluster にどのように移行できるかについて説明するステップバイステップガイドが含まれています。
パフォーマンスの特徴
MEMORY
のパフォーマンスは、更新処理時のシングルスレッド実行とテーブルロックオーバーヘッドが原因の競合によって抑制されます。このため、負荷が増えたときに拡張性が制限されます (特に、書き込みを含むステートメント混在時)。
MEMORY
テーブルのインメモリー処理にかかわらず、それらは、汎用目的クエリーのために、または読み取り/書き込み負荷では、必ずしもビジーサーバーの InnoDB
テーブルより高速である必要はありません。特に、更新実行に関与するテーブルロックは、複数セッションからの MEMORY
テーブルの並列使用の速度を低下させる可能性があります。
MEMORY
テーブルで実行されるクエリーの種類によっては、デフォルトのハッシュデータ構造 (一意キーで 1 つの値を検索する場合)、または汎用目的の B ツリーデータ構造 (等号、不等号、未満または「- を超える」などの範囲演算子などを含むすべての種類のクエリーの場合) のいずれかとしてインデックスを作成する場合があります。次のセクションでは、両方の種類のインデックスを作成するための構文について説明します。パフォーマンス面でよくある問題は、B ツリーインデックスがより効率的な作業負荷で、デフォルトのハッシュインデックスを使用していることです。
MEMORY テーブルの物理特性
MEMORY
ストレージエンジンは、各テーブルと 1 つのディスクファイル (テーブルの定義を格納 (データではありません)) を関連付けます。ファイル名はテーブル名から始まり、.frm
拡張子が付きます。
MEMORY
テーブルには次のような特徴があります。
MEMORY
テーブルの領域は小さなブロックに割り当てられます。テーブルは、挿入に 100% 動的ハッシュを使用します。オーバーフロー領域や余分なキー領域は必要ありません。フリーリスト用の余分な領域は必要ありません。削除された行はリンクリストに置かれ、新しいデータをテーブルに挿入するときに再利用されます。MEMORY
テーブルでは、ハッシュテーブルで一般的に削除 + 挿入に関連付けられる問題も起こりません。MEMORY
テーブルは固定長の行ストレージフォーマットを使用します。VARCHAR
などの可変長型は、固定長を使用して格納されます。MEMORY
テーブルはBLOB
またはTEXT
カラムを含むことができません。MEMORY
はAUTO_INCREMENT
カラムのサポートを含みます。TEMPORARY
MEMORY
でないテーブルは、ほかのTEMPORARY
でないテーブルと同様に、すべてのクライアントで共有されます。
MEMORY テーブルへの DDL 操作
MEMORY
テーブルを作成するには、CREATE TABLE
ステートメントで ENGINE=MEMORY
句を指定します。
CREATE TABLE t (i INT) ENGINE = MEMORY;
エンジンの名前が表すように、MEMORY
テーブルはメモリーに格納されます。デフォルトではハッシュインデックスを使用するため、単一値の検索には非常に高速であり、一時テーブルの作成には非常に役立ちます。ただし、サーバーがシャットダウンすると、MEMORY
テーブルに格納されたすべての行が失われます。テーブルの定義はディスク上の .frm
ファイルに格納されているため、テーブル自体は引き続き存在しますが、サーバーが再起動したときにテーブルは空になります。
この例は、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
ストレージエンジンは HASH
と BTREE
の両方のインデックスをサポートしています。ここに示すように 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
テーブルはストレージ変換の影響を受けませんが、内部一時テーブルは次のような影響があります。
内部一時テーブルが大きくなりすぎると、セクション8.4.4「MySQL が内部一時テーブルを使用する仕組み」で説明したように、サーバーは自動的にオンディスクストレージに変換します。
ユーザー作成の
MEMORY
テーブルは、決してディスクテーブルに変換されません。
データのロード
MySQL サーバーの起動時に MEMORY
テーブルを移入するには、--init-file
オプションを使用できます。たとえば、このファイルで INSERT INTO ... SELECT
や LOAD DATA INFILE
などのステートメントを実行することで、永続データソースからテーブルをロードできます。セクション5.1.3「サーバーコマンドオプション」およびセクション13.2.6「LOAD DATA INFILE 構文」を参照してください。
同時に別のセッションでアクセスされた MEMORY
テーブルにデータをロードするため、MEMORY
は INSERT DELAYED
をサポートしています。セクション13.2.5.2「INSERT DELAYED 構文」を参照してください。
MEMORY テーブルとレプリケーション
サーバーの MEMORY
テーブルは、シャットダウンされて再起動されたときに空になります。サーバーがレプリケーションマスターの場合は、そのスレーブはこれらのテーブルが空になったことを認識しないため、スレーブのテーブルからデータを選択した場合に内容が古いことがわかります。マスターとスレーブの MEMORY
テーブルの同期を取るため、MEMORY
テーブルが起動してからマスター側で最初に使用されたときに、スレーブ側でもテーブルを空にするため、DELETE
ステートメントがマスターのバイナリログに書かれます。スレーブでは、マスターの再起動とテーブルの最初の使用までの間は、テーブルのデータが古いままです。スレーブへの直接クエリーが古いデータを戻す可能性があるこの期間を避けるには、--init-file
オプションを使用して起動時にマスター上の 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で参照できます。