28.01.2015 Views

PZ3U6X

PZ3U6X

PZ3U6X

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

MySQLのロックについて<br />

JPOUG> SET EVENTS 20140907<br />

2014/09/07 平 塚 貞 夫<br />

Revision 2<br />

1


自 己 紹 介<br />

• DBエンジニアをやっています。 専 門 はOracle DatabaseとMySQL。<br />

• オープンソースソフトウェアの 導 入 支 援 をしています。<br />

• 仕 事 の 割 合 はOracle:MySQL:PostgreSQL=1:2:7くらいです。<br />

• Twitter:@sh2nd<br />

• はてな:sh2<br />

•<br />

• 写 真 は 実 家 で 飼 っているミニチュアダックスのオス、アトムです。<br />

2


本 日 のお 題<br />

3


想 定 外 のデッドロック<br />

• MySQLのInnoDBストレージエンジンに 対 して、2つのトランザクション<br />

を 以 下 の 順 番 で 実 行 するとデッドロックが 発 生 します。<br />

1:REPEATABLE_READ<br />

2:REPEATABLE_READ<br />

1:UPDATE:DELETE FROM emp WHERE empno = 7784<br />

(1:UPDATE:COUNT=0)<br />

2:UPDATE:DELETE FROM emp WHERE empno = 7786<br />

(2:UPDATE:COUNT=0)<br />

1:UPDATE:INSERT INTO emp (empno, ename) VALUES (7784, 'steve')<br />

2:UPDATE:INSERT INTO emp (empno, ename) VALUES (7786, 'bill')<br />

(1:UPDATE:COUNT=1)<br />

(2:UPDATE:COUNT=0)<br />

(2:com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:<br />

Deadlock found when trying to get lock; try restarting transaction)<br />

2:ABORT<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

• このデッドロックの 発 生 メカニズムを 理 解 するために、InnoDBのロック<br />

アーキテクチャについて 確 認 していきます。<br />

4


従 業 員 テーブル<br />

• emp( 従 業 員 )テーブルを 用 いて 確 認 していきます。<br />

empno( 社 員 番 号 )、ename( 社 員 名 )、job( 職 種 ),mgr( 上 司 の 社 員 番 号 )、<br />

hiredate( 入 社 日 )、sal( 給 料 )、comm( 歩 合 給 )、deptno( 部 門 番 号 )<br />

+-------+--------+-----------+------+------------+---------+---------+--------+<br />

| empno | ename | job | mgr | hiredate | sal | comm | deptno |<br />

+-------+--------+-----------+------+------------+---------+---------+--------+<br />

| 7369 | smith | clerk | 7902 | 1980-12-17 | 800.00 | NULL | 20 |<br />

| 7499 | allen | salesman | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |<br />

| 7521 | ward | salesman | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |<br />

| 7566 | jones | manager | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |<br />

| 7654 | martin | salesman | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |<br />

| 7698 | blake | manager | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |<br />

| 7782 | clark | manager | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |<br />

| 7788 | scott | analyst | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |<br />

| 7839 | king | president | NULL | 1981-11-17 | 5000.00 | NULL | 10 |<br />

| 7844 | turner | salesman | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |<br />

| 7876 | adams | clerk | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |<br />

| 7900 | james | clerk | 7698 | 1981-12-03 | 950.00 | NULL | 30 |<br />

| 7902 | ford | analyst | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |<br />

| 7934 | miller | clerk | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |<br />

+-------+--------+-----------+------+------------+---------+---------+--------+<br />

• empnoカラムにプライマリインデックス、jobカラムに 非 ユニークイン<br />

デックスを 作 成 してあります。<br />

5


InnoDBの 設 計 思 想<br />

6


トランザクション 処 理 概 念 と 技 法<br />

• InnoDBは「トランザクション 処 理 概 念 と 技 法 」という 本 の 内 容 を 参 考<br />

にして 実 装 されています。<br />

"The book by Jim Gray and Andreas Reuter, Transaction<br />

processing, from about year 1992, is the best reference. Much of<br />

InnoDB has been written according to the instructions in that book.<br />

- Heikki Tuuri"<br />

(http://lists.mysql.com/mysql/107555)<br />

• 洋 書 は 購 入 可 能 です。<br />

• 和 書 は 中 古 で 手 に 入 れるしかないと 思 います。<br />

7


ファントムリード<br />

• ファントムリードとは、 他 のトランザクションによってINSERTされたレ<br />

コードが 自 分 のトランザクションで 見 えてしまう 現 象 のことです。<br />

• READ COMMITTEDの 場 合 にファントムリードが 発 生 する 例 です。<br />

1:READ_COMMITTED<br />

2:READ_COMMITTED<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 ORDER BY empno<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2452.00 null 10 )<br />

(7788 scott analyst 7566 1987-04-19 3002.00 null 20 )<br />

(1:QUERY)<br />

2:UPDATE:INSERT INTO emp (empno, ename) VALUES (7785, 'steve')<br />

(2:UPDATE:COUNT=1)<br />

2:COMMIT<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 ORDER BY empno<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2452.00 null 10 )<br />

(7785 steve null null null null null null )<br />

(7788 scott analyst 7566 1987-04-19 3002.00 null 20 )<br />

(1:QUERY)<br />

8


ファントムリードを 防 ぐ<br />

• トランザクション 分 離 レベルの 定 義 によれば、ファントムリードは<br />

SERIALIZABLE 以 外 のトランザクション 分 離 レベルで 発 生 する 可 能 性 が<br />

あります。<br />

分 離 レベル ダーティリード ファジーリード ファントムリード<br />

READ UNCOMMITTED 可 能 性 あり 可 能 性 あり 可 能 性 あり<br />

READ COMMITTED 発 生 しない 可 能 性 あり 可 能 性 あり<br />

REPEATABLE READ<br />

(InnoDBのデフォルト)<br />

発 生 しない 発 生 しない 可 能 性 あり<br />

(InnoDBでは 発 生 しない)<br />

SERIALIZABLE 発 生 しない 発 生 しない 発 生 しない<br />

• 本 書 の 第 7 章 でトランザクション 分 離 性 における 課 題 としてファントム<br />

リードが 挙 げられており、それに 対 処 するために 述 語 ロック、 粒 度 ロッ<br />

ク、キー 範 囲 ロック、 後 方 キーロックや 前 方 キーロックといった 技 法 が<br />

紹 介 されています。<br />

• 多 くのDBMSがデフォルトのトランザクション 分 離 レベルをREAD<br />

COMMITTEDに 設 定 していますが、 本 書 の 内 容 を 参 考 にして 実 装 された<br />

InnoDBは、より 高 いトランザクション 分 離 性 を 実 現 することを 目 指 して<br />

いるように 見 受 けられます。<br />

9


ファントムリードを 防 ぐ 例 その1<br />

• InnoDBでトランザクション 分 離 レベルがREPEATABLE READの 場 合 は、<br />

ファントムリードを 防 ぐことが 可 能 です。<br />

• なおREPEATABLE READはファントムリードが 発 生 することを 許 容 して<br />

いますが、DBMS 側 の 都 合 により 発 生 しない 場 合 でも 定 義 上 の 問 題 はあ<br />

りません。<br />

1:REPEATABLE_READ<br />

2:READ_COMMITTED<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 ORDER BY empno<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2452.00 null 10 )<br />

(7788 scott analyst 7566 1987-04-19 3002.00 null 20 )<br />

(1:QUERY)<br />

2:UPDATE:INSERT INTO emp (empno, ename) VALUES (7785, 'steve')<br />

(2:UPDATE:COUNT=1)<br />

2:COMMIT<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 ORDER BY empno<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2452.00 null 10 )<br />

(7788 scott analyst 7566 1987-04-19 3002.00 null 20 )<br />

(1:QUERY)<br />

10


ファントムリードを 防 ぐ 例 その2<br />

• SELECT 文 にLOCK IN SHARE MODE、あるいはFOR UPDATE 句 を 付 与<br />

して 明 示 的 にロックを 取 得 することができます。これをロッキングリー<br />

ドと 呼 びます。<br />

• REPEATABLE READでロッキングリードを 行 うことによっても、ファン<br />

トムリードを 防 ぐことが 可 能 です。この 場 合 は 他 のトランザクションに<br />

よるINSERTが 待 たされます。<br />

1:REPEATABLE_READ<br />

2:READ_COMMITTED<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 ORDER BY empno LOCK IN SHARE MODE<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2452.00 null 10 )<br />

(7788 scott analyst 7566 1987-04-19 3002.00 null 20 )<br />

(1:QUERY)<br />

2:UPDATE:INSERT INTO emp (empno, ename) VALUES (7785, 'steve')<br />

(2:UPDATE:COUNT=0)<br />

(2:java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction)<br />

2:ABORT<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 ORDER BY empno<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2452.00 null 10 )<br />

(7788 scott analyst 7566 1987-04-19 3002.00 null 20 )<br />

(1:QUERY)<br />

11


MVCC 方 式 とロック 方 式<br />

• トランザクション 分 離 性 を 実 現 する 方 式 として、MVCC(Multi-Version<br />

Concurrency Control) 方 式 とロック 方 式 があります。<br />

• MVCC 方 式 ではSELECT 文 が 共 有 ロックを 取 得 せず、 他 のトランザクショ<br />

ンによる 更 新 があった 場 合 はUNDOを 用 いて 更 新 前 のデータを 見 せます。<br />

• ロック 方 式 では 先 行 するSQL 文 が 共 有 ロックまたは 排 他 ロックを 取 得 し、<br />

他 のトランザクションが 排 他 ロックを 取 得 して 行 う 更 新 を 待 たせます。<br />

(1)SELECT (3)SELECT<br />

(1)SELECT / DML<br />

(2)DML<br />

UNDO<br />

(2)DML<br />

MVCC 方 式<br />

ロック 方 式<br />

12


MVCC 方 式 とロック 方 式 の 使 い 分 け<br />

• InnoDBがMVCC 方 式 とロック 方 式 をどのように 使 い 分 けているのかを 以<br />

下 に 示 します。REPEATABLE READ 以 上 でネクストキーロックというも<br />

のを 取 得 するところ、それからSERIALIZABLEでSELECT 文 が 共 有 ロッ<br />

クを 取 得 するところが 特 徴 です。<br />

分 離 レベル SELECT LOCK IN<br />

SHARE MODE<br />

• Oracle Databaseの 場 合 は 以 下 のようになります。<br />

FOR UPDATE<br />

/ DML<br />

READ COMMITTED 文 単 位 のMVCC 共 有 レコードロック 排 他 レコードロック<br />

REPEATABLE READ<br />

トランザクション<br />

単 位 のMVCC<br />

共 有 ネクストキーロック<br />

排 他 ネクストキーロック<br />

SERIALIZABLE 共 有 ネクストキーロック 共 有 ネクストキーロック 排 他 ネクストキーロック<br />

分 離 レベル SELECT LOCK IN<br />

SHARE MODE<br />

FOR UPDATE<br />

/ DML<br />

READ COMMITTED 文 単 位 のMVCC (なし) 排 他 レコードロック<br />

(SET TRANSACTION<br />

READ ONLY)<br />

SERIALIZABLE<br />

トランザクション<br />

単 位 のMVCC<br />

トランザクション<br />

単 位 のMVCC<br />

(なし) ( 禁 止 )<br />

(なし)<br />

排 他 レコードロック<br />

(シリアル 化 エラーあり)<br />

13


ここまでのまとめ<br />

• InnoDBは「トランザクション 処 理 概 念 と 技 法 」という 本 の 内 容 を 参 考<br />

にして 実 装 されており、ファントムリードを 防 ぐことを 目 指 しているよ<br />

うに 見 受 けられます。<br />

• ファントムリードを 防 ぐためには、トランザクション 単 位 のMVCCを 実<br />

行 するか、あるいはネクストキーロックというものを 取 得 します。<br />

14


InnoDBのロックアーキテクチャ<br />

15


テーブルの 構 造<br />

• InnoDBは、プライマリインデックスのリーフノードにデータを 格 納 する<br />

クラスタインデックス 構 造 を 採 用 しています。Oracle Databaseで 言 う<br />

索 引 構 成 表 です。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

16


インデックスの 構 造<br />

• プライマリインデックス 以 外 のインデックスのことを、セカンダリイン<br />

デックスと 呼 びます。セカンダリインデックスはリーフノードにプライ<br />

マリキーの 値 を 格 納 しており、セカンダリインデックスを 走 査 したあと<br />

プライマリインデックスを 走 査 することで 目 的 のレコードを 取 得 します。<br />

セカンダリ<br />

インデックス<br />

プライマリ<br />

インデックス<br />

analyst<br />

(7788)<br />

manager<br />

(7698)<br />

manager<br />

(7782)<br />

president<br />

(7839)<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

• Oracle Databaseの 場 合 はインデックスのリーフノードにレコードの 物<br />

理 的 な 位 置 を 示 すROWIDを 格 納 しており、インデックスを2 回 走 査 する<br />

ことはありません。


レコードロック<br />

• InnoDBはインデックス 上 のレコードをロックすることでレコードロック<br />

を 行 います。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

7788(scott)に 対 するレコードロック<br />

18


ギャップロック<br />

• InnoDBではインデックス 上 のレコードとレコードの 間 がロックされるこ<br />

とがあります。これをギャップロックと 呼 びます。<br />

• ロック 方 式 でファントムリードを 防 ぐには、 現 時 点 で 存 在 しないレコー<br />

ドをロックする 必 要 があります。ギャップロックは 存 在 しないレコード<br />

を 低 コストでロックするために 導 入 された 仕 組 みです。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

7788(scott)の 手 前 に 対 するギャップロック<br />

19


ネクストキーロック<br />

• レコードロックとその 手 前 のギャップロックを 合 わせて、ネクストキー<br />

ロックと 呼 びます。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

7788(scott)に 対 するネクストキーロック<br />

20


ロックの 範 囲<br />

• SELECT LOCK IN SHARE MODE、SELECT FOR UPDATEやDMLを 実<br />

行 すると、InnoDBはインデックス 上 で 走 査 したレコードに 対 してレコー<br />

ドロック、ギャップロックまたはネクストキーロックを 取 得 します。<br />

• 検 索 条 件 に 合 致 したレコードに 対 してではなく、 走 査 したレコードに 対<br />

してロックを 取 得 するというところが 特 徴 です。InnoDBはあくまで<br />

MySQLのストレージエンジンであり、 検 索 時 にすべての 検 索 条 件 を 把 握<br />

できているわけではないことが 要 因 の 一 つだと 考 えられます。<br />

21


ここまでのまとめ<br />

• InnoDBはクラスタインデックス 構 造 を 採 用 しています。<br />

• インデックス 上 のレコードをロックすることでレコードロックを 行 いま<br />

す。<br />

• ファントムリードを 防 ぐために、レコードとレコードの 間 をロックする<br />

仕 組 みが 導 入 されています。<br />

• インデックス 上 で 走 査 したレコードに 対 してロックを 取 得 します。<br />

22


REPEATABLE READにおけるロック 範 囲<br />

23


プライマリインデックスに 対 する 等 価 検 索<br />

SELECT * FROM emp WHERE empno = 7788 FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7788(scott)に 対 するレコードロック<br />

• ファントムリードが 発 生 する 余 地 はないため、ギャップロックは 取 得 さ<br />

れません。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

24


プライマリインデックスに 対 するIN 検 索<br />

SELECT * FROM emp WHERE empno IN (7782, 7788) FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7782(clark)、7788(scott)に 対 するレコードロック<br />

• IN 検 索 は、 等 価 検 索 を 複 数 回 実 行 することと 同 じです。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

25


プライマリインデックスに 対 する 範 囲 検 索<br />

SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7782(clark)に 対 するレコードロック<br />

• 7788(scott)、7839(king)に 対 するネクストキーロック<br />

• 範 囲 検 索 の 場 合 はリーフノードのリスト 構 造 を 走 査 し、7839(king)まで<br />

走 査 して 止 まります。そのため 一 つ 先 の7839(king)に 対 してもネクスト<br />

キーロックが 取 得 されます。ロックの 範 囲 が 広 くなることに 注 意 が 必 要<br />

です。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

26


プライマリインデックスに 対 する 範 囲 検 索 + 追 加 条 件<br />

SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 AND ename LIKE '%t' FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7782(clark)に 対 するレコードロック<br />

• 7788(scott)、7839(king)に 対 するネクストキーロック<br />

• 7782(clark)と7839(king)は 追 加 条 件 に 合 致 しませんが、ロックは 取 得<br />

されたままとなります。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

27


プライマリインデックスに 対 する 等 価 検 索 、 空 振 り<br />

SELECT * FROM emp WHERE empno = 7785 FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7788(scott)の 手 前 に 対 するギャップロック<br />

• 検 索 条 件 に 合 致 した 場 合 はレコードロックが 取 得 されますが、 空 振 りし<br />

た 場 合 はギャップロックが 取 得 されます。ロックの 範 囲 が 広 くなること<br />

に 注 意 が 必 要 です。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

28


プライマリインデックスに 対 する 範 囲 検 索 、 空 振 り<br />

SELECT * FROM emp WHERE empno BETWEEN 7784 AND 7786 FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7788(scott)に 対 するネクストキーロック<br />

• 範 囲 検 索 ではリーフノードのリスト 構 造 を 走 査 しますが、この 場 合 は<br />

7788(scott)だけを 走 査 して 止 まります。7788(scott)に 対 してネクスト<br />

キーロックが 取 得 されます。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

29


非 ユニークインデックスに 対 する 範 囲 条 件<br />

SELECT * FROM emp WHERE job BETWEEN 'analyst' AND 'manager' FOR UPDATE<br />

• セカンダリインデックスに 対 する 以 下 のロックが 取 得 されます。<br />

• analyst(7788)、manager(7698)、manager(7782)、<br />

president(7839)に 対 するネクストキーロック<br />

• プライマリインデックスに 対 する 以 下 のロックが 取 得 されます。<br />

• 7698(blake)、7782(clark)、7788(scott)に 対 するレコードロック<br />

• それぞれのインデックスに 対 してロックが 取 得 されます。<br />

セカンダリ<br />

インデックス<br />

プライマリ<br />

インデックス<br />

analyst<br />

(7788)<br />

manager<br />

(7698)<br />

manager<br />

(7782)<br />

president<br />

(7839)<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

30


非 ユニークインデックスに 対 する 等 価 条 件<br />

SELECT * FROM emp WHERE job = 'manager' FOR UPDATE<br />

• セカンダリインデックスに 対 する 以 下 のロックが 取 得 されます。<br />

• manager(7698)、manager(7782)に 対 するネクストキーロック<br />

• president(7839)の 手 前 に 対 するギャップロック<br />

• プライマリインデックスに 対 する 以 下 のロックが 取 得 されます。<br />

• 7698(blake)、7782(clark)に 対 するレコードロック<br />

• 非 ユニークインデックスの 場 合 は、 等 価 条 件 であっても 範 囲 条 件 に 近 い<br />

挙 動 となります。また、 一 つ 先 のpresident(7839)に 対 してはネクスト<br />

キーロックではなくギャップロックが 取 得 されます。<br />

セカンダリ<br />

インデックス<br />

プライマリ<br />

インデックス<br />

analyst<br />

(7788)<br />

manager<br />

(7698)<br />

manager<br />

(7782)<br />

president<br />

(7839)<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

31


非 ユニークインデックスに 対 する 等 価 条 件 、フルスキャン<br />

SELECT * FROM emp IGNORE INDEX (emp_job) WHERE job = 'manager' FOR UPDATE<br />

• プライマリインデックスに 対 する 以 下 のロックが 取 得 されます。<br />

• 7698(blake)、7782(clark)、7788(scott)、7839(king)、<br />

supremumに 対 するネクストキーロック<br />

• InnoDBは 走 査 したレコードに 対 してロックを 取 得 するため、SQL 実 行 計<br />

画 が 変 化 するとロックの 範 囲 も 変 化 します。<br />

• supremumとは、 内 部 的 に 設 けられている 上 限 値 のレコードです。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

supremum<br />

32


ここまでのまとめ<br />

• プライマリインデックスに 対 する 等 価 検 索 の 場 合 は、レコードロックが<br />

取 得 されます。<br />

• プライマリインデックスに 対 する 範 囲 検 索 の 場 合 は、 走 査 したレコード<br />

に 対 するレコードロックまたはネクストキーロックが 取 得 されます。ま<br />

た、 一 つ 先 のレコードまで 走 査 します。<br />

• 検 索 が 空 振 りした 場 合 は、ギャップロックまたはネクストキーロックが<br />

取 得 されます。<br />

• 非 ユニークインデックスの 場 合 は、セカンダリインデックスとプライマ<br />

リインデックスのそれぞれに 対 してロックが 取 得 されます。また、 等 価<br />

条 件 であっても 範 囲 条 件 に 近 い 挙 動 となります。<br />

• SQL 実 行 計 画 が 変 化 するとロックの 範 囲 も 変 化 します。<br />

33


READ COMMITTEDにおけるロック 範 囲<br />

34


プライマリインデックスに 対 する 範 囲 検 索<br />

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED<br />

SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7782(clark)、7788(scott)、7839(king)に 対 するレコードロック<br />

• SQL 文 の 完 了 時 に 以 下 のロックが 解 放 されます。<br />

• 7839(king)に 対 するレコードロック<br />

• READ COMMITTEDはファントムリードを 許 容 するため、ギャップロッ<br />

クは 取 得 されません。また、 検 索 条 件 に 合 致 しなかったレコードに 対 す<br />

るロックはSQL 文 の 完 了 時 に 解 放 されます。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

35


プライマリインデックスに 対 する 範 囲 検 索 + 追 加 条 件<br />

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED<br />

SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 AND ename LIKE '%t' FOR UPDATE<br />

• 以 下 のロックが 取 得 されます。<br />

• 7782(clark)、7788(scott)、7839(king)に 対 するレコードロック<br />

• SQL 文 の 完 了 時 に 以 下 のロックが 解 放 されます。<br />

• 7782(clark)、7839(king)に 対 するレコードロック<br />

• インデックスが 関 与 しない 追 加 条 件 についても、 合 致 しなかったレコー<br />

ドに 対 するロックはSQL 文 の 完 了 時 に 解 放 されます。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

36


トランザクションの 順 番 による 挙 動 の 違 い<br />

• 一 時 的 に7782(clark)、7839(king)に 対 するレコードロックを 取 得 する<br />

ため、トランザクションの 順 番 によって 挙 動 が 変 わります。<br />

• 後 続 トランザクションは7782(clark)のロックを 取 得 することが 可 能 です。<br />

1:READ_COMMITTED<br />

2:READ_COMMITTED<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 AND ename LIKE '%t' FOR UPDATE<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7788 scott analyst 7566 1987-04-19 3000.00 null 20 )<br />

(1:QUERY)<br />

2:QUERY:SELECT * FROM emp WHERE empno = 7782 FOR UPDATE<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2450.00 null 10 )<br />

(2:QUERY)<br />

• 一 方 、7782(clark)のロックを 取 得 している 先 行 トランザクションがある<br />

と 待 たされます。<br />

2:READ_COMMITTED<br />

1:READ_COMMITTED<br />

2:QUERY:SELECT * FROM emp WHERE empno = 7782 FOR UPDATE<br />

(empno ename job mgr hiredate sal comm deptno )<br />

(7782 clark manager 7839 1981-06-09 2450.00 null 10 )<br />

(2:QUERY)<br />

1:QUERY:SELECT * FROM emp WHERE empno BETWEEN 7782 AND 7788 AND ename LIKE '%t' FOR UPDATE<br />

(1:QUERY)<br />

(1:java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction)<br />

1:ABORT<br />

37


プライマリインデックスに 対 する 等 価 検 索 、 空 振 り<br />

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED<br />

SELECT * FROM emp WHERE empno = 7785 FOR UPDATE<br />

• ロックは 取 得 されません。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

38


プライマリインデックスに 対 する 範 囲 検 索 、 空 振 り<br />

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED<br />

SELECT * FROM emp WHERE empno BETWEEN 7784 AND 7786 FOR UPDATE<br />

• ロックは 取 得 されません。<br />

プライマリインデックス<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

39


ここまでのまとめ<br />

• READ COMMITTEDの 場 合 は、ギャップロックは 取 得 されません。<br />

• 走 査 したレコードに 対 するレコードロックが 取 得 されますが、 検 索 条 件<br />

に 合 致 しなかったレコードに 対 するロックはSQL 文 の 完 了 時 に 解 放 され<br />

ます。<br />

• 検 索 が 空 振 りした 場 合 は、ロックは 取 得 されません。<br />

40


調 査 方 法<br />

41


InnoDBロックモニタ<br />

• MySQL 5.6.16 以 降 でパラメータinnodb_status_output_locksを 有 効 に<br />

すると、SHOW ENGINE INNODB STATUSコマンドでロックの 状 態 を<br />

確 認 できます。この 機 能 のことをInnoDBロックモニタと 呼 びます。<br />

SET GLOBAL innodb_status_output_locks = ON<br />

SHOW ENGINE INNODB STATUS<br />

• 実 行 例 を 以 下 に 示 します。<br />

SELECT * FROM emp WHERE empno BETWEEN 7698 AND 7782 OR empno = 7835 FOR UPDATE ← 7835は 空 振 り<br />

RECORD LOCKS space id 342 page no 3 n bits 88 index `PRIMARY` of table `scott`.`emp` trx id 1857327<br />

lock_mode X locks rec but not gap ← 7698(blake)に 対 するレコードロック<br />

Record lock, heap no 7 PHYSICAL RECORD: n_fields 10; compact format; info bits 0<br />

0: len 4; hex 80001e12; asc ;; ← 10 進 数 で7698<br />

RECORD LOCKS space id 342 page no 3 n bits 88 index `PRIMARY` of table `scott`.`emp` trx id 1857327<br />

lock_mode X<br />

← 7782(clark)と7788(scott)に 対 するネクストキーロック<br />

Record lock, heap no 8 PHYSICAL RECORD: n_fields 10; compact format; info bits 0<br />

0: len 4; hex 80001e66; asc f;; ← 10 進 数 で7782<br />

Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0<br />

0: len 4; hex 80001e6c; asc l;; ← 10 進 数 で7788<br />

RECORD LOCKS space id 342 page no 3 n bits 88 index `PRIMARY` of table `scott`.`emp` trx id 1857327<br />

lock_mode X locks gap before rec ← 7839(king)の 手 前 に 対 するギャップロック<br />

Record lock, heap no 10 PHYSICAL RECORD: n_fields 10; compact format; info bits 0<br />

0: len 4; hex 80001e9f; asc ;; ← 10 進 数 で7839<br />

42


本 日 のお 題 ( 再 )<br />

43


デッドロックの 発 生 メカニズム<br />

1. TX1のDELETE 文 が 空 振 りし、7788(scott)の 手 前 のギャップロックを 取 得 します。<br />

1:UPDATE:DELETE FROM emp WHERE empno = 7784<br />

7698<br />

(blake)<br />

7782<br />

(clark)<br />

2. TX2のDELETE 文 が 空 振 りし、7788(scott)の 手 前 のギャップロックを 取 得 します。なお<br />

ギャップロック 同 士 は 競 合 しません。<br />

2:UPDATE:DELETE FROM emp WHERE empno = 7786<br />

7788<br />

(scott)<br />

7839<br />

(king)<br />

3. TX1のINSERT 文 が7788(scott)の 手 前 のギャップに 対 して 挿 入 インテンションギャップロッ<br />

クの 取 得 を 試 み、TX2のギャップロックと 競 合 します。 挿 入 インテンションギャップロック<br />

とは、INSERT 文 の 実 行 時 に 取 得 される 特 殊 なギャップロックです。 挿 入 インテンション<br />

ギャップロック 同 士 は 競 合 せず、 通 常 のギャップロックと 競 合 します。<br />

1:UPDATE:INSERT INTO emp (empno, ename) VALUES (7784, 'steve')<br />

4. TX2のINSERT 文 が7788(scott)の 手 前 のギャップに 対 して 挿 入 インテンションギャップロッ<br />

クの 取 得 を 試 み、TX1のギャップロックと 競 合 してデッドロックが 発 生 します。<br />

2:UPDATE:INSERT INTO emp (empno, ename) VALUES (7786, 'bill')<br />

44


宿 題<br />

• 対 処 方 法 を 考 えてみてください。<br />

45

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!