簡略化して、プライマリ自動インクリメントフィールドapp_idを持つテーブル「app」と、nullではない1つのフィールドcreated_at datetimeがあります。
「app_id」という単一のキーを持つ「app_subset」という別のテーブルがあります。
このようなクエリを実行すると:
SELECT app_id FROM app;
それが実行されている間、私は実行します:
INSERT INTO app (created_at) VALUES (NOW());
挿入は、selectの終了を待たずに、すぐに実行されます。
ただし、次のようなクエリを実行するとします。
INSERT IGNORE INTO app_subset SELECT app_id FROM app;
次に、同じ挿入をアプリに実行します。
INSERT INTO app (created_at) VALUES (NOW());
これで、INSERT INTOアプリのクエリブロックが実行され、INSERT IGNOREが完了するのを待機します。
私はこれが事実である理由を理解しようとしています。私の選択の結果がINSERT INTOアプリによって変更されることを理解していますが、元のSELECTがブロックしない場合、その選択の結果を使用したINSERTもブロックしないはずです。何らかの形でこれが当てはまるように設定できるようにしたい、または少なくとも同じような問題が発生する理由を少なくとも完全に理解して、今後同様の問題を予測できるようにしたいと考えています。
以下のRolandoの回答から、READ UNCOMMITEDは機能するはずであり、実際に私が実行すると次のようになります:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
INSERT IGNORE .. SELECTによって、INSERT INTOアプリがブロックされなくなりました。
単一の行としてそれを行う方法があるかどうか知りたいです(次のようなもの)。
INSERT IGNORE INTO app_subset SELECT app_id FROM app LOCK IN NONSHARING MODE;
実際、INSERT INTO .. SELECT
はSELECT
テーブルをロックします
私は前にこれについて書いた
Apr 25, 2016
: MySQL INSERT ... SELECTパフォーマンスAug 08, 2014
: MySQLの一貫した非ロック読み取りとINSERT ... SELECTの比較 (詳細)