LoginSignup
13
3

More than 1 year has passed since last update.

MySQLのINSERT SELECTでロックを回避する方法

Last updated at Posted at 2021-12-14

INSERT INTO SELECT FROM構文とは?

任意の条件でSELECTした結果を別のテーブルにINSERTする構文です。

複数レコードを一括で挿入するため、1レコードずつ処理するより高速に動作し
SQLで完結するためアプリケーションサーバのメモリにも優しいです。

各種サマリー作成の他、単純なテーブルのコピーにも便利です。

INSERT INTO SELECT FROMのロック

高速に動作し、日常的に書くことの多い構文ですが、ロックが設定されるため注意が必要です。
以下、MySQLのデフォルトであるREPEATABLE READのトランザクション分離レベルを利用した場合です。

INSERT側テーブルはロックなし

公式ドキュメントにauto incrementが指定されている場合、
更新用の特殊な排他ロックが設定される記載がありますが
読み込み、書き込みともにスムーズに流れます。

SELECT側テーブルは共有ネクストキーロック

共有ロックのため読み込みは流れますが、書き込みは待ち状態になります。
ロック対象はSELECTの探査と共に増加し、INSERTの完了まで解除されないため
書き込み頻度の高いテーブルから大量のデータを移動する用途では
高確率でタイムアウトが発生します。

ロックを回避するためには?

INSERT INTO B SELECT * FROM A;

単純なテーブルコピーを行う場合の回避策の検討です。

方法1. トランザクション分離レベルの変更

# トランザクション分離レベルの変更
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

INSERT INTO B SELECT * FROM A;

トランザクション分離レベルを変更してSELECT側のロックを回避します。

ファントムリードなどが発生する可能性がありますが、
修正が容易で対応工数は少なくすみます。

方法2. TEMPテーブルにスナップショットを退避

# トランザクション分離レベルの変更
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

# 中間テーブルを作成
CREATE TEMPORARY TABLE C AS SELECT * FROM A;

# 中間テーブルからコピー
INSERT INTO B SELECT * FROM C;

SELECT側のロックを回避した状態で、
セッション内でしか読み書きされない中間テーブルを作成しています。

中間テーブルのロックを気にする必要がなく、
途中からトランザクションを開始することも可能です。

データの整形やINSERT前の検証が必要な場合に便利な折衷案ですが
データコピーが2回走るため、実行時間は2倍に伸びます。

方法3. LOAD DATA IN (LOCAL) FILEの利用

# ファイル作成
SELECT * FROM A INTO OUTFILE '/tmp/a.tsv';

# ファイル読み込み
LOAD DATA LOCAL INFILE '/tmp/a.tsv' INTO TABLE B;

同じく複数レコードを一括挿入する目的の構文です。
INSERT文より高速に動作し、SELECTのロックはFOR UPDATEなどで任意に指定可能です。

ローカルにファイルが作成されるため、
多重実行時の保存場所やセキュリティ、ディスク容量など考えることが多くなります。

エスケープや区切り文字にも気をつかう必要があり、
必然的に対応工数は肥大化しがちです。

まとめ

書き込み頻度が少ないマスタデータなどでは
そもそも共有ロックの影響を気にする必要はありません。

LOAD DATA IN FILEは優れた代替案ですが、
精度が求められない、内部向けデータ集計などのオペレーションでは、
トランザクション分離レベルの変更は便利な選択肢です。

一長一短あるので、用途に応じて使い分けができると幸せになれます。

採用PR

弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください!

13
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3