INSERT DELAYED ...
INSERT
ステートメントの
DELAYED
オプションは、もし
INSERT
が完了するのを待つ事ができない、または待つ必要がないクライアントを持っている場合に大変有効となる、スタンダード
SQL の MySQL 拡張子です。これは、MySQL
をログに利用し、完了までに長時間かかる
SELECT
と UPDATE
ステートメントを定期的に起動させる時によく起こる状態です。
クライアントが INSERT DELAYED
を利用する時、サーバからすぐに OK
が出て、テーブルが別のスレッドによって使用中でなければ行が挿入される為にキューを作ります。
INSERT DELAYED
を利用する事のそれ以外の大きな利益は、たくさんのクライアントからの挿入は一緒にまとめられ、ひとつのブロックに書き込まれると言う事です。これは、別々の挿入を何度も行うよりも早く機能します。
INSERT DELAYED
は、もしテーブルが他の形で利用されていないのであれば、通常の
INSERT
よりも遅いという事に注意してください。また、サーバには、遅れている行を持つ各テーブルに別々のスレッドを扱う為の、追加オーバーヘッドもあります。これは、本当に
INSERT DELAYED
が必要だという事が確実な時だけ利用するべきであるという事を意味します。
キューを作った行は、テーブルに挿入されるまでメモリ内だけで保持されます。これは、もしmysqld
を強制的に終了させたり (例えば、kill
-9
を利用して)、mysqld
が突然停止してしまったりすると、ディスクに書き込まれる前のキューを作った行は全て失われてしまう
という事を意味します。
DELAYED
の利用に関しては、いくつかの制限があります。
INSERT DELAYED
は
MyISAM
、MEMORY
、そして
ARCHIVE
テーブルとのみ機能します。項13.4. 「MyISAM
ストレージエンジン」、項13.7. 「MEMORY
(HEAP
)
ストレージエンジン」、そして
項13.10. 「ARCHIVE
ストレージエンジン」
を参照してください。
もしデータファイル中にフリー
ブロックがなければ、MyISAM
テーブルには並列 SELECT
と
INSERT
ステートメントがサポートされます。これらの条件下では、INSERT
DELAYED
を MyISAM
と一緒に利用しなければいけない事はほとんどありません。
INSERT DELAYED
は、値リストを指定する
INSERT
ステートメントにだけ利用されなければいけません。サーバは、INSERT
... SELECT
か INSERT ... ON DUPLICATE
KEY UPDATE
に対して
DELAYED
を無視します。
INSERT DELAYED
ステートメントがすぐに返されるので、そのステートメントが生成するであろう
AUTO_INCREMENT
値を得る為に、行が挿入される前に、LAST_INSERT_ID()
を利用する事はできません。
DELAYED
行は、実際に挿入されるまでは
SELECT
ステートメントには見えません。
DELAYED
は、スレーブにマスタとは異なるデータを持たせる事があるので、スレーブ複製サーバ上では無視されます。
テーブルが書き込みロックされ、ALTER
TABLE
がテーブル構造を変更するのに利用されると、保留中の
INSERT DELAYED
ステートメントは失われてしまいます。
INSERT DELAYED
は画面をサポートしません。
次に、INSERT
や
REPLACE
に DELAYED
を利用した時に何が起こるかを詳しく説明しています。この説明の中では、「スレッド」
は INSERT DELAYED
ステートメントを受け取ったスレッドで、「ハンドラ」
は特定のテーブルの為に全ての INSERT
DELAYED
ステートメントを扱うスレッドを表しています。
スレッドが DELAYED
ステートメントをテーブルに実行した時、もし同じようなハンドラが既に存在していなければ、全ての
DELAYED
ステートメントをテーブルに生成する為にハンドラ
スレッドが作成されます。
スレッドは、ハンドラが以前に
DELAYED
ロックを習得したかどうかを確認します。もし習得していなければ、ハンドラ
スレッドに対して習得するよう命令します。もし他のスレッドが
READ
か WRITE
ロックをテーブル上に持っていても、DELAYED
ロックを得る事ができます。しかし、ハンドラはテーブル構造が最新であるかどうかを確認する為に、全ての
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
が全てのメモリを使わない事を保障する為に行われます。
ハンドラスレッドは、Command
カラム内の delayed_insert
と共に、MySQL プロセス
リスト内に現れます。これは、もし
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
コマンドを実行する事でこれらの変数を見る事ができます。