INSERT DELAYED ...
INSERT
の完了を待てないクライアントがある場合、MySQL
固有のオプションである DELAYED
を指定した INSERT
ステートメントが非常に役立ちます。このようなクライアントの問題は、MySQL
を使用してログを記録する一方で、完了までに時間がかかる
SELECT
や UPDATE
ステートメントを定期的に実行している場合によく起こります。DELAYED
は、MySQL バージョン 3.22.15
で導入された、SQL-92 に対する MySQL
の拡張です。
INSERT DELAYED
は、ISAM
および
MyISAM
テーブルに対してのみ作用します。注意:
MyISAM
テーブルでは、データファイルの中央に空きブロックがない場合、同時
SELECT
と同時 INSERT
が可能なため、MyISAM
テーブルで
INSERT DELAYED
を使用する必要はほとんどありません。 See
項7.1. 「MyISAM
テーブル」。
INSERT DELAYED
を使用すると、クライアントは直ちに処理の続行を許可されます。そして、テーブルが別のスレッドによって使用されていなければ、レコードが挿入されます。
INSERT DELAYED
のもう 1
つの主な利点は、多くのクライアントによる挿入が
1 つにまとめられて、1
ブロックに書き込まれることです。この場合、数多くの挿入を個別に行うより、処理速度がはるかに速くなります。
注意:
現在のところ、キューに入れられたレコードは、テーブルに挿入されるまでは単にメモリに格納されているに過ぎません。つまり、mysqld
を kill -9
によって強制終了した場合や、mysqld
が予期しない状況で突然終了した場合、ディスクに書き込まれていないキューの中のレコードはすべて消失します。
以下に、INSERT
または
REPLACE
ステートメントで
DELAYED
オプションを指定した場合の処理について詳しく説明します。この説明中、``スレッド''
は INSERT DELAYED
コマンドを受け取ったスレッドを指し、``ハンドラ''
は個々のテーブルの INSERT DELAYED
ステートをすべて処理するスレッドを指します。
スレッドがいずれかのテーブルに対する
DELAYED
ステートメントを実行すると、そのテーブルのすべての
DELAYED
ステートメントを処理するハンドラスレッドが作成される(このようなハンドラがすでに存在しない場合)。
スレッドは、ハンドラが
DELAYED
ロックをすでに取得しているかチェックし、まだの場合はロックを取得するようハンドラに指示する。DELAYED
ロックは、他のスレッドがそのテーブルに対する
READ
または WRITE
ロックを持っている場合でも取得できる。ただし、その場合ハンドラは、必ず最新のテーブル構造が得られるよう、すべての
ALTER TABLE
ロックまたは
FLUSH TABLES
が完了するまで待機する。
スレッドは INSERT
ステートメントを実行する。ただし、この場合、スレッドはレコードをテーブルに書き込む代わりに、ハンドラスレッドが管理するキューに最後のレコードのコピーを入れる。構文エラーがある場合はスレッドによって検出され、クライアントプログラムに報告される。
クライアントは重複の数や結果のレコードの
AUTO_INCREMENT
値はいずれも報告できない。INSERT
は挿入処理が完了する前に戻るため、クライアントはこれらの情報をサーバから取得できない。C
API
を使用している場合、同じ理由で、mysql_info()
関数でも、意味のある情報は何も返されない。
バイナリログは、レコードがテーブルに挿入されると、ハンドラスレッドによって更新される。複数のレコードの挿入時では、バイナリログは最初のレコードが挿入された時点で更新される。
各 delayed_insert_limit
レコードが書き込まれると、そのつど、ハンドラはまだ保留中になっている
SELECT
ステートメントがないかチェックする。ある場合、ハンドラは処理を続行する前に保留中のステートメントの実行を許可する。
ハンドラのキューにレコードが何もなくなると、テーブルのロックが解除される。delayed_insert_timeout
に指定された秒数が経過する前に、新しい
INSERT DELAYED
コマンドが渡されないと、ハンドラは終了する。
delayed_queue_size
に指定された数を超えるレコードが特定のハンドラキューにすでに保留になっていると、INSERT
DELAYED
を要求しているスレッドはキューに空きスペースができるまで待機する。これは、mysqld
サーバで遅延メモリキューのメモリをすべて使ってしまわないようにするためである。
ハンドラスレッドは MySQL プロセスリストの
Command
カラムに
delayed_insert
として表示される。FLUSH TABLES
コマンドを実行するか、または KILL
thread_id
を使用して強制終了すると、ハンドラスレッドは強制終了される。しかし、この場合ハンドラスレッドは、キュー内のすべてのレコードをテーブルに格納してから終了する。この間、ハンドラスレッドは別のスレッドからの新しい
INSERT
コマンドをまったく受け入れない。この後に
INSERT DELAYED
コマンドを実行すると、新しいハンドラスレッドが作成される。
注意:これは、すでに実行されている
INSERT DELAYED
が存在する場合、通常の
INSERT
コマンドより
INSERT DELAYED
コマンドの方が優先されることを意味する。他の更新コマンドは、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
コマンドを実行する。
注意:
対象のテーブルが使用中でない場合、INSERT
DELAYED
は通常の INSERT
より遅くなります。また、INSERT
DELAYED
を使用する各テーブルに対応するスレッドを個別に処理するためにサーバで追加のオーバーヘッドが発生します。そのため、INSERT
DELAYED
はどうしても使う必要があるときのみ使用してください。
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.