ロックする読み取り、UPDATE
、または
DELETE
は通常、SQL
ステートメントの処理の中でスキャンされる全てのインデックス
レコード上にレコード
ロックを設定します。行を排除するステートメント内に
WHERE
条件があればそれは問題ではありません。InnoDB
は正確な WHERE
条件を記憶しませんが、どのインデックス範囲がスキャンされたのかは分かっています。レコード
ロックは通常、レコードの前に
「ギャップ」
への挿入も速やかにブロックするネクスト キー
ロックです。
もし設定されるロックが専用であれば、InnoDB
は常にクラスタ化されたインデックス
レコードの検索と、それに対するロックの設定もします。
もしご自分のステートメントに適応したインデックスがなく、MySQL がステートメントを処理する為にテーブル全体をスキャンしなければいけないなら、テーブルの全ての行がロックされ、それはその代わりにテーブルへの別のユーザによる全ての挿入をブロックします。クエリが不必要にたくさんの行をスキャンする必要がなくなるように、よいインデックスを作成する事が重要です。
InnoDB
は次のように特定のロック
タイプを設定します:
SELECT ... FROM
は一貫した読み取りであり、データベースのスナップショットを読み取り、トランザクションの分離レベルが
SERIALIZABLE
に設定されなければロックは設定しません。これは、SERIALIZABLE
レベルに対して、直面するインデックス
レコード上に共有ネクスト キー
ロックを設定します。
SELECT ... FROM ... LOCK IN SHARE MODE
は、その読み取りが直面する全てのインデックス
レコード上に共有ネクスト キー
ロックを設定します。
SELECT ... FROM ... FOR UPDATE
は、その読み取りが直面する全てのインデックス
レコード上に専用共有ネクスト キー
ロックを設定します。
INSERT INTO ... VALUES (...)
は挿入された行上に専用ロックを設定します。このロックはネクスト
キー
ロックではなく、挿入された行の前のギャップに別のユーザが挿入する事を防ぎます。もし複製キー
エラーが発生すると、複製インデックス
レコード上の共有ロックが設定されます。
テーブル上であらかじめ指定された
AUTO_INCREMENT
カラムを初期化している間、InnoDB
は AUTO_INCREMENT
カラムと関係しているインデックスの最後に専用ロックを設定します。
自動インクリメント
カウンタにアクセスする時、InnoDB
は、トランザクション全体の最後までではなく、現在の
SQL
ステートメントの最後まで続く、特別なテーブル
ロック モード AUTO-INC
を利用します。AUTO-INC
テーブル
ロックが行われている間は、別のクライアントはテーブルに挿入ができない事に注意してください。
項13.5.10.2. 「InnoDB
と AUTOCOMMIT
」
を参照してください。
InnoDB
は、ロックを設定せずに、あらかじめ初期化された
AUTO_INCREMENT
カラムの値をフェッチします。
INSERT INTO T SELECT ... FROM S WHERE ...
は T
に挿入された各行上に専用(ネクスト
キーではない)ロックを設定します。InnoDB
は、innodb_locks_unsafe_for_binlog
が有効でなければ共有ネクスト キー
ロックを S
に設定し、その場合それは S
に対して一貫した読み取りとしての検索を行います。InnoDB
は後者の場合にロックを設定する必要があります:バックアップからの前進復旧では、全ての
SQL
ステートメントはそれが元々行われたのと全く同じ方法で実行されなければいけません。
CREATE TABLE ... SELECT ...
は、前出の項目のように、SELECT
を一貫した読み取りとして、または共有ロックを利用して実行します。
REPLACE
は、もし固有キーにコリジョンがなければ挿入と同じように行われます。反対に、専用ネクスト
キー
ロックは更新されなければいけない行上に置かれます。
UPDATE ... WHERE ...
は、検索が直面する全てのレコード上に専用ネクスト
キー ロックを設定します。
DELETE FROM ... WHERE ...
は、検索が直面する全てのレコード上に専用ネクスト
キー ロックを設定します。
もし FOREIGN KEY
制約がテーブル上で定義されると、確認される制約条件を要求する全ての挿入、更新、または削除が、制約を確認する為に参照するレコード上に共有レコード
レベル
ロックを設定します。InnoDB
も、制約が失敗する場合に備えてこれらのロックを設定します。
LOCK TABLES
はテーブル
ロックを設定しますが、これはこれらのロックを設定する
InnoDB
レイヤより上位の MySQL
レイヤです。InnoDB
は
innodb_table_locks=1
(デフォルト)と
AUTOCOMMIT=0
であればテーブル
ロックを認識しており、また
InnoDB
より上位の MySQL
レイヤは行レベル
ロックを識別します。そうでなければ、InnoDB
の自動デッドロック検出は、そのようなテーブル
ロックが関連しているデッドロックを検出する事はできません。
また、上位の MySQL レイヤは行レベル
ロックを識別しないので、別のユーザが現在行レベル
ロックを持っているテーブル上にテーブル
ロックを得る事が可能です。しかし、項13.5.10.10. 「デッドロックの検出とロールバック」
で説明されているように、これはトランザクション
インテグリティを危険にさらしたりはしません。項13.5.16. 「InnoDB
テーブル上の制約」
もご参照ください。