PZ3U6X
PZ3U6X
PZ3U6X
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