innodbでサブクエリを使ったときの FOR UPDATE のロックの範囲


前提として、次の通りテーブルを使用する。

CREATE TABLE A
(
  id INT NOT NULL,
  no INT NOT NULL,
  PRIMARY KEY (id, no)
);

CREATE TABLE B
(
  id INT NOT NULL,
  PRIMARY KEY (id)
);


普通に結合すると A と B の両方の行がロックされる。

SELECT *
FROM A INNER JOIN B USING (id)
WHERE A.id = 1 AND A.no = 1
FOR UPDATE


サブクエリの中で FOR UPDATE すれば、サブクエリの中の A だけがロックされ、外側の B はロックされない。

SELECT *
FROM (
  SELECT * FROM A WHERE A.id = 1 AND A.no = 1 FOR UPDATE
) X INNER JOIN B USING (id)


逆に、サブクエリの外側で FOR UPDATE した場合、サブクエリの中の A はロックされず、外側の B だけがロックされる。

SELECT *
FROM (
  SELECT * FROM A WHERE A.id = 1 AND A.no = 1
) X INNER JOIN B USING (id)
FOR UPDATE


相関サブクエリの場合も、サブクエリの外側で FOR UPDATE していれば、外側の A だけがロックされ、内側の B はロックされない。

SELECT *
FROM A
WHERE A.id = 1 AND A.no = 1 AND EXISTS ( SELECT * FROM B WHERE B.id = A.id )
FOR UPDATE