はじめに
100人が同時に、映画館予約システムの「予約」ボタンを押した、
といったシナリオを考えてみます。
テーブル定義はこんな感じ、
座席番号 | 予約状況 |
---|---|
A1 | NO |
A2 | YES |
B1 | NO |
... | ... |
複数トランザクションから同時に、空席の問い合わせと予約状況の更新が走ります。
MySQLを使って、トランザクション間でロック待ちを起こさずに、実現できるでしょうか。
ロックされているレコードの行ロック解放を待たずに処理続行できたらいいが。。。
Oracleにはそのための NOWAIT と SKIP LOCKED オプションがありますね。
それが、MySQLも 8.0 から同じオプション使えるよ、と同僚が教えてくれました(えー、知らなかったの?とお声が)。
MySQL 8 で、NOWAIT と SKIP LOCKED オプション の定義
引用元: https://dev.mysql.com/blog-archive/mysql-8-0-1-using-skip-locked-and-nowait-to-handle-hot-rows/
- NOWAIT
A locking read that uses NOWAIT never waits to acquire a row lock.
The query executes immediately, failing with an error if a requested row is locked.
- SKIP LOCKED
A locking read that uses SKIP LOCKED never waits to acquire a row lock.
The query executes immediately, removing locked rows from the result set.
これで、獲得可能なロックのみ獲得し即時に結果を返せるので(両者の違いはエラーを返すか返さないか)、
行ロックが解放されるまで待機する必要がなくなり、さくっと空席を予約できそうです。
注意書き
データ一貫性は担保できない、と特記事項ありました。
Note
Queries that skip locked rows return an inconsistent view of the data.
SKIP LOCKED is therefore not suitable for general transactional work.
However, it may be used to avoid lock contention when multiple sessions
access the same queue-like table.
別トランザクションによりロックかけられているレコードはスキップされ、
問い合わせ結果に含まれないので、当たり前のことかもしれません。
ですので、
- 行競合が発生しうる並列処理を分散させたい
- ただし、問い合わせ結果に抜け漏れが出でもOK
のような場面で使用できそうです。
おわりに
MySQL 8 からの NOWAIT と SKIP LOCKED オプションを用いて、
期待とおり、さくっと座席予約できるか、そのパフォーマンスはいかがなものか、
など、検証してみたいですね。
お楽しみに。