あの“津崎さん”も保有する難関資格「データベーススペシャリスト」。本企画では、データベーススペシャリスト試験 午前/午後試験対策のための「基礎知識」を抜粋してお届けします。今回は「排他制御」の基礎を解説します。
書籍の中から有用な技術情報をピックアップして紹介する本シリーズ。今回は、秀和システム発行の書籍ポケットスタディ データベーススペシャリスト [第2版](2015年12月22日発行)』からの抜粋です。
ご注意:本稿は、著者及び出版社の許可を得て、そのまま転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。
※編集部注:前回記事「原子性を実現する「コミットメント制御」を理解する」はこちら
出題頻度 午前II:●●- 午後I:●-- 午後II:---
●--:過去14年間での過去問出題数が1〜9回
●●-:過去14年間での過去問出題数が10〜19回
●●●:過去14年間での過去問出題数が20回以上
●排他制御、同時実行制御、ロックの種類・粒度、2相ロッキングプロトコル、デッドロック対策、待ちグラフ、時刻印方式、楽観的方式
ACID特性の要素であるトランザクションの一貫性・独立性を確保するため、DBMSには排他制御(同時実行制御)機能が備わっています。この排他制御は主にデータベースのロックにより実現されます。ロックとは、あるトランザクションがデータを操作している間は、他のトランザクションがデータを操作できないように制限をかけることです。
ロックには占有ロックと共有ロックの2種類があります。
ロックの種類 | ロックの特徴 |
---|---|
占有ロック | あるデータにこのロックをかけると、ロックをかけている間、他のトランザクションが共有ロックも占有ロックもかけることができなくなる。データを更新する時に利用する |
共有ロック | あるデータにこのロックをかけると、ロックを掛けている間、他のトランザクションが占有ロックをかけられなくなる。データを参照する時に利用する |
上記のロックは下表の関係を持ちます。これにより「データ更新中は、他の処理により更新・参照ともにできず、データ参照中は他のトランザクションから参照はできるが更新はできない」ということが実現できます。
1回のロックでロックを掛ける範囲をロックの粒度(りゅうど)と呼び、具体的には、表単位、行単位という粒度があります。それぞれ一長一短があるので、システムの特徴により使い分けが必要になります。
粒度 | 待ち時間 | 回数 | 使い分け方 |
---|---|---|---|
表単位(荒い) | 長い | 少ない | ロック回数が少なく、CPU負荷が少ないため一度に多くのデータを更新する場合に向く |
行単位(細かい) | 短い | 多い | 待ち時間が短く、並行作業を行いやすいため、小さな更新が頻繁に起きる場合に向く |
DBMSは、排他制御を行うために、データを操作する前にロックをかけ(第1相)、操作後にロックを解除する(第2相)というロックのルールを用いてトランザクションの実行を制御します。この方式を2相ロッキングプロトコルと呼びます。
尚、一度ロックを解除したら、そのトランザクション内で、再度ロックをかけることはできません。
2つ以上のトランザクションにより、「お互いがロックしている資源について、お互いがロック解除を待つ状態になること」をデッドロックと呼びます。例えば以下の2つのトランザクションがA、Bの順で開始し、(1)〜(4)の順で処理が行われた場合、デッドロックが発生します。
デッドロックを検出するには、「トランザクションの待ち時間を監視し、一定時間の待ちが続いた場合にデッドロックが起きたと見なす」方法(時間監視)と、「どの資源をどのトランザクションがロックし、他のどのトランザクションが待っているかを示した待ちグラフという有向グラフを作成する」方法の2種類があります。
デッドロックを解除するためには、デッドロックを起こしているトランザクションを特定し、一方を強制終了(ロールバック)させます。
上図「デッドロックの発生例」では、トランザクションAとBで、各資源a、bをロックする順序が逆になっています。このような場合にデッドロックが発生する可能性があります。逆に、全てのトランザクションで資源をロックする順序を(a→b)のように統一すれば、デッドロックは発生しません。
DBMSの排他制御はロック方式が主流ですが、それ以外の排他制御として、「時刻印方式」と「楽観的方式」があります。ロックという概念がないため、当然デッドロックは発生しませんが、やはり一長一短があります。
時刻印方式では、トランザクションの開始時、データ読取り・書出し時などの時刻(タイムスタンプ)を記録します。複数のトランザクションが競合した際、タイムスタンプにより、最初に実行されたトランザクションを特定し、これを先に実行するよう、一旦、他の全てのトランザクションをロールバックした後、再実行します。競合が多発するとスループットが低下しやすいため、トランザクション間で共有する資源が少ない場合に有効です。
楽観的方式では、トランザクション開始前に、読み込んだデータのコピーを取得します。(以降、データを書き込む直前まで排他制御を行いません。)データを書き込む際に、「書き込み先のデータが他のトランザクションにより更新されていないか」をコピーと比較することで確認し、該当データが他のトランザクションにより更新されていなければ処理を続行します。更新されていた場合はロールバックし、処理を最初からやり直します。
Copyright © ITmedia, Inc. All Rights Reserved.