INSERT DELAYED ...
INSERT
ステートメントの DELAYED
オプションは、特定の種類のテーブル (MyISAM
など) に使用できる、標準 SQL への MySQL 拡張です。クライアントが INSERT DELAYED
を使用すると、サーバーからはただちに了解が得られ、行は、そのテーブルがほかのどのスレッドによっても使用されていないときに挿入されるようにキューに入れられます。
INSERT DELAYED
は、そのテーブルがほかで使用されていなければ、通常の INSERT
より低速です。また、サーバーが、遅延された行が存在するテーブルごとに個別のスレッドを処理するための追加のオーバーヘッドもあります。つまり、INSERT DELAYED
は、それが必要なことを実際に確信している場合にのみ使用するようにしてください。
MySQL 5.6.6 現在、INSERT DELAYED
は非推奨であり、将来のリリースで削除されます。代わりに INSERT
(DELAYED
を付けない) を使用してください。
キューに入れられた行は、テーブルに挿入されるまで、メモリー内にのみ保持されます。つまり、mysqld を強制的に (たとえば、kill -9
で) 終了した場合や、mysqld が予期せず終了した場合は、まだディスクに書き込まれていないキューに入れられたすべての行が失われます。
DELAYED
の使用には、次のいくつかの制約があります。
INSERT DELAYED
は、MyISAM
、MEMORY
、ARCHIVE
、およびBLACKHOLE
テーブルでのみ機能します。DELAYED
をサポートしていないエンジンの場合は、エラーが発生します。挿入は、ロックを保持するセッションではなく、別のスレッドによって処理される必要があるため、
LOCK TABLES
を使用してロックされたテーブルで使用された場合は、INSERT DELAYED
に対してエラーが発生します。MyISAM
テーブルでは、データファイルの途中に空きブロックが存在しない場合は、並列SELECT
およびINSERT
ステートメントがサポートされます。これらの状況では、MyISAM
でINSERT DELAYED
を使用する必要はほとんどありません。INSERT DELAYED
は、値リストを指定するINSERT
ステートメントでのみ使用するようにしてください。サーバーは、INSERT ... SELECT
またはINSERT ... ON DUPLICATE KEY UPDATE
ステートメントでのDELAYED
を無視します。INSERT DELAYED
ステートメントはただちに復帰するため、行が挿入される前に、LAST_INSERT_ID()
を使用して、このステートメントによって生成される可能性のあるAUTO_INCREMENT
値を取得することはできません。DELAYED
行は、実際に挿入されるまで、SELECT
ステートメントには表示されません。-
MySQL 5.6 より前は、ステートメントが複数の行を挿入し、バイナリロギングが有効になっており、かつグローバルロギング形式がステートメントベースである (つまり、
binlog_format
がSTATEMENT
に設定されているときは必ず) 場合、INSERT DELAYED
は通常のINSERT
として処理されました。MySQL 5.6 からは、binlog_format
の値がSTATEMENT
またはMIXED
である場合は必ず、INSERT DELAYED
は常に、単純な (つまり、DELAYED
オプションのない)INSERT
として処理されます。(後者の場合、このステートメントは行ベースのロギングへの切り替えをトリガーしなくなったため、そのステートメントベースの形式を使用してログに記録されます。)これは、行ベースのバイナリロギングモードを使用している (
binlog_format
がROW
に設定されている) 場合は適用されません。この場合、INSERT DELAYED
ステートメントは常に、指定のとおりにDELAYED
オプションを使用して実行され、行更新イベントとしてログに記録されます。 INSERT DELAYED
がスレーブ上で通常のINSERT
として処理されるように、DELAYED
はスレーブレプリケーションサーバー上で無視されます。これは、DELAYED
のために、スレーブにマスターとは異なるデータが存在することになる場合があるためです。テーブルが書き込みロックされているときに、そのテーブル構造を変更するために
ALTER TABLE
が使用されると、保留中のINSERT DELAYED
ステートメントは失われます。INSERT DELAYED
は、ビューではサポートされません。INSERT DELAYED
は、パーティション化されたテーブルではサポートされません。
次に、INSERT
または REPLACE
に対して DELAYED
オプションを使用したときの動作について詳細に説明します。この説明では、「スレッド」は INSERT DELAYED
ステートメントを受信したスレッドであり、「ハンドラ」は、特定のテーブルに対するすべての INSERT DELAYED
ステートメントを処理するスレッドです。
スレッドがあるテーブルに対する
DELAYED
ステートメントを実行すると、そのテーブルに対するすべてのDELAYED
ステートメントを処理するためのハンドラスレッドが作成されます (このようなハンドラがまだ存在しない場合)。このスレッドは、そのハンドラが以前に
DELAYED
ロックを取得したかどうかをチェックします。取得していない場合は、それを行うようハンドラスレッドに指示します。DELAYED
ロックは、ほかのスレッドがそのテーブルに対するREAD
またはWRITE
ロックを保持している場合でも取得できます。ただし、ハンドラはテーブル構造を確実に最新の状態にするために、すべてのALTER TABLE
ロックまたはFLUSH TABLES
ステートメントが完了するのを待機します。このスレッドは
INSERT
ステートメントを実行しますが、行をテーブルに書き込む代わりに、最終行のコピーをそのハンドラスレッドによって管理されているキューに配置します。構文エラーはすべてスレッドによって検出され、クライアントプログラムにレポートされます。INSERT
は挿入操作が完了する前に復帰するため、クライアントは重複した行の数や、結果として得られる行のAUTO_INCREMENT
値をサーバーから取得できません。(C API を使用している場合も、同じ理由で、mysql_info()
関数は意味のある情報を何も返しません。)バイナリログは、行がテーブルに挿入されたときにハンドラスレッドによって更新されます。複数行の挿入の場合、バイナリログは、先頭行が挿入されたときに更新されます。
delayed_insert_limit
行が書き込まれるたびに、ハンドラは、いずれかのSELECT
ステートメントが引き続き保留中かどうかをチェックします。保留中の場合は、続行する前に、これらの実行を許可します。ハンドラのキューにそれ以上行がなくなると、テーブルはロック解除されます。新しい
INSERT DELAYED
ステートメントがdelayed_insert_timeout
秒以内に受信されなかった場合、ハンドラは終了します。特定のハンドラキュー内で
delayed_queue_size
を超える行が保留中である場合、INSERT DELAYED
を要求しているスレッドは、そのキューに空きができるまで待機します。これは、遅延されたメモリーキューのすべてのメモリーが mysqld によって使用されてしまわないようにするために行われます。-
このハンドラスレッドは、MySQL プロセスリストの
Command
カラム内にdelayed_insert
として現れます。これは、FLUSH TABLES
ステートメントを実行するか、またはKILL
で強制終了すると強制終了されます。ただし、終了する前に、まずキューに入れられたすべての行をテーブルに格納します。この時間中は、ほかのスレッドからの新しいどのthread_id
INSERT
ステートメントも受け入れません。このあとにINSERT DELAYED
ステートメントを実行すると、新しいハンドラスレッドが作成されます。つまり、実行中の
INSERT DELAYED
ハンドラが存在する場合、INSERT DELAYED
ステートメントは通常のINSERT
ステートメントより高い優先度を持っています。その他の更新ステートメントは、INSERT DELAYED
キューが空になるか、だれかが (KILL
で) このハンドラスレッドを終了するか、またはだれかがthread_id
FLUSH TABLES
を実行するまで待機する必要があります。 -
次のステータス変数は、
INSERT DELAYED
ステートメントに関する情報を提供します。ステータス変数 意味 Delayed_insert_threads
ハンドラスレッドの数 Delayed_writes
INSERT DELAYED
で書き込まれた行数Not_flushed_delayed_rows
書き込みを待機している行数 これらの変数は、
SHOW STATUS
ステートメントを発行するか、または mysqladmin extended-status コマンドを実行することによって表示できます。