📖

Oracleの待機とロック

2023/06/29に公開

Oracleの待機とロック

こんにちは!わいわわです。
今回はOracleの待機について学習し、
その発生要因である各種ロックについて学習します。

システムを運用していると、多くのシステムではデータベース内に待機が発生し、
性能が出なかったり、処理遅延が発生したりします。
この待機の仕組みを正しく理解し、チューニングや遅延の解消を行う知識をつけます!

ロックの必要性

データの中身を変更したいとします。
その場合のロジックとして、
1.まず数字を知りたいから、取り出す(SELECT)
2.その後、取り出した値に1を足して再び格納する(UPDATE)
これで機能しそうに見えますね!

しかし、これでは問題が起きる可能性があり、
それが「並列処理を行ってしまった場合」です。
並列処理をすると実行するタイミングによっては値が増えないという現象が起きます。

例えば、OracleクライアントAとBが同時に上記作業を行った場合
2.の数値に1を足して格納するUPDATEが2回おこなわれます。
データは2ですが、期待値としては3になってしまうのです。

これはデータが保護されていなかったため、起きた問題だと言えます。
つまり、データの変更作業中は変更前のデータを参照する検索作業を除いて、
そのデータに誰も触れることができないようにしなくてはならないということですね。

OracleクライアントAがデータを変更している間は、
A以外は同じデータを変更できないように
変更対象のデータにロックをかけて保護しなくてはならなかったのです。

このようにロックの本質は
多重処理を実現するために、データの保護を実装する」ことにあります。
SQLではSELECTの段階でロックをかけることができます。
ロックが解放となるのはコミット時、もしくはロールバックの時です。

実はUPDATE文などのSML(データ操作言語)には
自動的に行ロックをかけてくれる仕組みがあります。
そのため、並列の処理しても正しい値になってくれるのです。

しかし大量に同時に動かそうとしたら行ロックで性能がでない場合ももちろんあり、
この場合はロックによる大気になってしまいますね。

アプリケーション側でこのような処理をしないよう、工夫をする必要があります、

ロック待ちの仕組み

待機イベント…待っている出来事
待機はSQL文の処理が遅くなることも多くあるため一般にはイメージが悪いですが
待機にも様々な種類があります。

・処理がないために暇な状態の待機
・理由があって仕方ない待機
・異常事態などの余計にSQL処理を待たせる待機

最初の1つ目をアイドル待機といい、
あとの2つをまとめてアイドルではない待機ということがあります。

アイドル待機イベントは準備ができている状態のようなものなので
SQL処理を待たせません。
そのためパフォーマンス分析の際には注目しないのが普通です。

「SQL*Net Message from client」

などが主な待機イベントです。
上記はクライアントからのSQL文などを待っているときの状態になります。

アイドルではない待機

問題はアイドルではない待機イベントになります。
理由があって仕方のない大気の例としては
正常なディスクI/O待ちがあります。

OracleはSQL処理の途中でデータが必要になった場合などに
ディスクからブロックを読み込むためその際に待機が発生してしまいます。
これはSQL処理に必要な待機といえます。

異常事態などの余計にSQL処理を待たせる待機がより厄介で、
たとえばあるユーザーがある表に対してロックをかけたまま食事行ってしまったりなどです。
これではほかのユーザーはその表のデータの変更ができず、余計な待ちです。

またディスクの故障などでI/O処理は大きく時間がかることもあります。
すると、待機時間は長くなり、その分SQL処理が待たされます。
これもエンドユーザーからすれば正常時より遅くなったという意味で余計な待機ですね。

同じ待機イベントでも、これらのように仕方のないものと異常なもの」があります。

SQL処理のチューニングという観点からは
「アイドルではない待機イベント+SQL処理のCPU時間」
がおおよそのSQL処理にかかった時間になるため、
チューニングする際には常に意識することが大切です。

待機イベントは「Statspack」「v$session_wait」から見ることができます。

ロックによる待機

ロックをかけているだけでは待機になりません。
ロックがかかっている対象にロックをかけようとすると待機が発生します。
ロックの情報はv$lockビューなどで確認できます。

v$lockビューでよくあるロックは「TX」と「TM」です。
TXはいわゆる行ロックで、TMは表にかけるロックです。
「モード」は同時実行性を制御するためのもので、
ロックがどのような状態でかかっているかを表します。

たとえばTXロックのX(排他)は、同一業に対するほかのモードのロックを許しません。
それに対して、DMLの際に取得されることの多いRX(またはRS)モードのTMロック(表ロック)は
他のセッションが同一の表に対してRX(またはRS)モードでTMロックを取得できます。

RXモードのロックがかかっていれば、表の定義変更などは防ぎつつ、
表に対する複数のトランザクションを許すことができます。

このように、モードをうまく使い分けることによって
必要な排他制御を実現しながら最大の同時実行性を実現させています。

デッドロック...お互いが他人の持つロックを持ってしまい、ずっと処理が進められない状態のこと。
起こった際には「デッドロックグラフ」というデッドロックの情報が記録されます。

ラッチについて

ラッチも多重処理を実現するためのロックです。
Oracle内部で自動的取得され、1回のSQL文の実行で数多くのデータの取得と開放を繰り返すことです。
メモリーやデータなど、操作する際に排他制御をしておかないとデータを壊してしまう危険があるものを保護します。

実はStatspackを見ると、ラッチは何十、何百と存在します。
できる限りロックを分解して、ロックの種類と数を増やすことにより、
他のセッションと競合する可能性を低くしているイメージです。
このような工夫によってOracleではラッチの競合は起こりづらくなっています。

ラッチの競合が起きる場合

CPUとOSの関係で起きることがあります。
OSはマルチタスクで多くの数の処理を実行でき、
プリエンプションという、処理中のCPUの横取りも行われます。

このプリエンプションなどのOSの動作が
ロックやラッチを持ったセッションからCPUを横取りすると
ラッチをもったセッションはCPUを使えなくなるため処理が進まず
CPUを使えるセッションはラッチをつかめずに処理が進まないという状況が発生します。
ラッチ競合が見られたらまずはCPU町を起こさせないようにすることが大事です。

まとめ

・アイドル待機イベントとアイドルではない待機イベントがある
・ロックはデータを保護するためにある
・デッドロックはお互いが所有するロックを要求して処理が進まない状況である
・ロック競合を解消するためには、アプリケーション側で対処しなければならないことが多い
・ラッチはOracle内部の大事なもの(主にメモリ)を保護するためにある
・大規模ではないシステムにおいてラッチ競合が激しいようであれば、
 CPUリソース不足か、ページングなどの望ましくない状態になっていないかどうかも確認する
・Oracleを健全に動かすためには、土台となるOSも健全な状態でなければならない

所感

今回はOracleの待機とロックについて学習しました。
処理が遅くなった時などの裏で起こっていることがイメージできました。
実務ではチューニングする機会もあると思うので、
就いた際は学習したことを活かして頑張ります!

Discussion