1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[前回] MySQL8の同時実行制御検証(2)

はじめに

前回は、二人同時に予約ボタンを押した場合、遅延なく制御できるか確認しました。
今回は、100人同時に予約ボタンを押した、といった想定です。
前回同様、映画館予約を例に、SKIP LOCKEDオプションを検証します。

座席番号(seat_id) 予約状況(ordered)
A1 NO
A2 YES
B1 NO
... ...

おさらいとして、予約処理は1トランザクションで完結、2ステップで構成されます。

  1. 空席を見つける
  2. 予約状況をNOからYESに、予約確定

検証スタートします、検証環境や事前準備は、前回をご参照ください。

検証シナリオ

100人が同時に「予約」ボタンを押した場合、

  1. 100人全員が予約できるか(1万自由席)
  2. 予約までどれだけ待たされるか

を確認します。
比較のため、下記二つのトランザクションをそれぞれ実行します。

  • トランザクション1
    SKIP LOCKED オプションあり、空席見つけてから、予約状況をYESに変更
START TRANSACTION;
SELECT @seat:=seat_id FROM theater WHERE ordered="NO" LIMIT 1 FOR UPDATE SKIP LOCKED;
UPDATE theater SET ordered="YES" WHERE seat_id=@seat;
COMMIT;
  • トランザクション2
    SKIP LOCKED オプションなし、空席見つけてから、予約状況をYESに変更
START TRANSACTION;
SELECT @seat:=seat_id FROM theater WHERE ordered="NO" LIMIT 1 FOR UPDATE;
UPDATE theater SET ordered="YES" WHERE seat_id=@seat;
COMMIT;

100人が同時にトランザクション1を実行

  • mysqlコマンドで、全席の予約状況をNOに初期化
mysql> UPDATE theater SET ordered='NO';
  • shellスクリプトで、100セッションから同時にトランザクション1を実行
$ for ((i=1;i<=100;i++));do time mysql -uuser -pxxx test -e 'START TRANSACTION; SELECT @seat:=seat_id FROM theater WHERE ordered="NO" LIMIT 1 FOR UPDATE SKIP LOCKED; UPDATE theater SET ordered="YES" WHERE seat_id=@seat; COMMIT;' >>query1.log & done 2> time1.log
  • 100人全員予約できたか確認
mysql> SELECT COUNT(*) FROM theater WHERE ordered='YES';
+----------+
| COUNT(*) |
+----------+
|      100 |
+----------+

全員予約できています。

  • 100人それぞれの予約にかかった時間を確認

time1.logにtimeコマンドによる計測時間が出力されています。

... ...

real    0m0.051s
user    0m0.006s
sys     0m0.000s

real    0m0.072s
user    0m0.005s
sys     0m0.000s
... ...

一番長く待たされた人は、82ミリ秒でした。

$ grep real time1.log | cut -c 8-12 | sort | tail -1
0.082
  • 座席番号の予約順を確認

座席がどのような順序で予約されたか、query1.logに記録されています。

... ...
@seat:=seat_id
1
@seat:=seat_id
12
@seat:=seat_id
5
... ...

座席順には関係なく予約されていく様子が窺えます。

100人が同時にトランザクション2を実行

  • mysqlコマンドで、全席の予約状況をNOに初期化
mysql> UPDATE theater SET ordered='NO';
  • shellスクリプトで、100セッションから同時にトランザクション2を実行
$ for ((i=1;i<=100;i++));do time mysql -uuser -pxxx test -e 'START TRANSACTION; SELECT @seat:=seat_id FROM theater WHERE ordered="NO" LIMIT 1 FOR UPDATE; UPDATE theater SET ordered="YES" WHERE seat_id=@seat; COMMIT;' >>query2.log & done 2> time2.log
  • 100人全員予約できたか確認
mysql> SELECT COUNT(*) FROM theater WHERE ordered='YES';
+----------+
| COUNT(*) |
+----------+
|      100 |
+----------+

こちらも全員予約できました。

  • 100人それぞれの予約にかかった時間を確認

time2.logにtimeコマンドによる計測時間が出力されています。

... ...
real    0m0.646s
user    0m0.006s
sys     0m0.000s

real    0m0.661s
user    0m0.006s
sys     0m0.000s
... ...

一番長く待たされた人は、661ミリ秒でした。

$ grep real time2.log | cut -c 8-12 | sort | tail -1
0.661
  • 座席番号の予約順を確認

座席がどのような順序で予約されたか、query2.logに記録されています。

... ...
@seat:=seat_id
1
@seat:=seat_id
2
@seat:=seat_id
3
... ...

座席が順を追って予約されていく様子が窺えます(一つずつ処理が終わるまで待つ)。

検証結果の考察

SKIP LOCKEDオプションあり・なしで、検証結果を比較すると

  • 100人全員が予約できたかについて
    • 両者ともOK
  • 予約までどれだけ待たされたかについて
    • SKIP LOCKEDにより、待ち時間がなんと1/8まで短縮されています(0.082s/0.661s)

おわりに

100ユーザによる同時予約で、SKIP LOCKEDオプションの効果抜群でした。
次回は別のテーマでMySQL 8の並列処理を検証してみます、お楽しみに。

1
0
0

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?