MySQLのインデックスによるロックの違いを確認してみる

VirtualBoxにCentOSをとりあえずインストール
の続き

MySQLのインデックスによるロックの違いを確認してみる。

【参考】
ロック待ちでハマる前に知りたかったMySQL InnoDBの行ロックとテーブルロックの挙動 | 三度の飯とエレクトロン
http://blog.katty.in/3082

準備

とりあえずMySQLをインストールする。

$ sudo yum -y install mysql-server
$ sudo service mysqld start
$ sudo chkconfig mysqld on

今回は、testデータベースを使う。

$ mysql -u root
mysql> use test

確認用のテーブルを作成する。

mysql> create table sample (
  id   int primary key auto_increment,
  name varchar(32) not null,
  val  int not null
) engine=innoDB default charset=utf8;

データを追加して

mysql> insert into sample (name, val)values
('satou', 0),
('suzuki', 0),
('takahashi', 0),
('tanaka', 0),
('ito', 0);

下記のような状態。

mysql> select * from sample;
+----+-----------+-----+
| id | name      | val |
+----+-----------+-----+
|  1 | satou     |   0 |
|  2 | suzuki    |   0 |
|  3 | takahashi |   0 |
|  4 | tanaka    |   0 |
|  5 | ito       |   0 |
+----+-----------+-----+

ターミナルを2つ立ち上げ、mysqlへの接続を2つ用意する。
以降、一つ目を

mysql1>

2つ目を

mysql2>

と記す。


update …

インデックスあり

idカラムを条件にして、更新。コミットしていない状態。

mysql1> begin;
mysql1> update sample set val = 0 where id = 2;

別の行を更新すると、すぐ更新できる。

mysql2> update sample set val = 0 where id = 3;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1  Changed: 0  Warnings: 0

同じ行だと待たされる。

mysql2> update sample set val = 0 where id = 2;
(待たされる)

インデックスのあるカラムを条件に更新した場合は行ロックになっている。

インデックスなし

nameカラムを条件にして、更新。コミットしていない状態。

mysql1> begin;
mysql1> update sample set val = 0 where name = 'suzuki';

別の行を更新すると、待たされる。

mysql2> update sample set val = 0 where id = 3;
(待たされる)

インデックスのないカラムを条件に更新した場合はテーブルロックになっている。


select … lock in share mode

インデックスあり

idカラムを条件にして、lock in share modeで検索。コミットしていない状態。

msyql1> begin;
mysql1> select * from sample where id = 2 lock in share mode;

別の行を更新すると、すぐ更新できる。

mysql2> update sample set val = 0 where id = 3;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1  Changed: 0  Warnings: 0

同じ行だと待たされる。

mysql2> update sample set val = 0 where id = 2;
(待たされる)

インデックスのあるカラムを条件にlock in share modeで検索した場合は行ロックになっている。

インデックスなし

nameカラムを条件にして、lock in share modeで検索。コミットしていない状態。

mysql1> begin;
mysql1> select * from sample where name = 'suzuki' lock in share mode;

別の行を更新すると、待たされる。

mysql2> update sample set val = 0 where id = 3;
(待たされる)

インデックスのないカラムを条件にlock in share modeで検索した場合はテーブルロックになっている。


select … for update

インデックスあり

idカラムを条件にして、for updateで検索。コミットしていない状態。

msyql1> begin;
mysql1> select * from sample where id = 2 for update;

別の行を検索すると、すぐ検索できる。

mysql2> select * from sample where id = 3 for update;
+----+-----------+-----+
| id | name      | val |
+----+-----------+-----+
|  3 | takahashi |   0 |
+----+-----------+-----+
1 row in set (0.00 sec)

同じ行だと待たされる。

mysql2> select * from sample where id = 2 for update;
(待たされる)

インデックスのあるカラムを条件にfor updateで検索した場合は行ロックになっている。

インデックスなし

nameカラムを条件にして、for updateで検索。コミットしていない状態。

msyql1> begin;
mysql1> select * from sample where name = 'suzuki' for update;

別の行を検索すると、待たされる。

mysql2> select * from sample where id = 3 for update;
(待たされる)

インデックスのないカラムを条件にfor updateで検索した場合はテーブルロックになっている。


結果

今回確認した結果。

検索条件のカラム インデックスあり インデックスなし
update … 行ロック テーブルロック
select … lock in share mode 行ロック テーブルロック
select … for update 行ロック テーブルロック