📚

REDOとUNDOについて学習する

2023/07/01に公開

REDOとUNDOについて学習する

こんにちは!わいわわです。
Oracleの学習を進めています。
今回はOracleのREDOとUNDOについて学習していきます!

ACID特性

トランザクションが備えなければいけない特性に「ACID」という特性があります。
この特性とREDOとUNDOは密接に関係しているため、
まずはACID特性から理解していきます。

A(Atomicity):原子性

トランザクションに含まれるデータ変更は、
「すべてOK」か「すべてNG」のどちらかです。
DBMSには一部のみ変更するというデータ変更は行いません。

そのため、原子性という特徴を持つといえます。

C(Consistency):一貫性

トランザクションによってデータ間の不整合を起こしてはならないという意味です。
不整合の例としては、
「顧客表のデータは更新されているのに、顧客表のインデックスのデータは変更されていない」
といったものがあります。

I(Isolation):分離性

トランザクション同士は分離されていて、独立しているという意味です。
あるトランザクションを単独で実行しても、
別のトランザクションと同時に実行しても結果は同じということです。

ただ、DBMSによってはどの程度分離させるかというレベルを選べます。

D(Durability):持続性
コミットされたトランザクションは、障害があっても
データが復旧されなければいけないという意味です。

ACIDの特徴まとめ

・マシンがダウンしても、コミットされたデータは復旧できなければいけない
・中途半端なデータ変更は行うことができない
・トランザクション単位で変更(もしくはロールバック)されなければならない
・ほかのトランザクションと同時に実行してもしなくても、結果は同じ

持続性の実現

コミットされたデータを守る特性の実装については
コミットされたデータをそのタイミングでディスクに書き出せばよさそうですね。

ただし、ディスクI/Oの時間のほとんどは「頭出し」の時間で占められています。
この方法では大量のデータを変更した場合、
COMMITに非常に長い時間がかかってしまいます。

そこでDBMSの多くは、ログ(更新ログ)を採用することによって
性能と持続性の両立を実現しています。
Oracleも同様で、REDOログによって性能と持続性を確保しているんですね。

REDOログにデータをまとめて書き込むことでI/O回数が減るためと、
シーケンシャルアクセスになるため、I/Oサイズが大きくなっても頭出しの回数は変わらないのです。

また、このREDOログで「誰が何をした」という情報を得、
もしデータでアクシデントが起き、復旧しないといけない状況が発生した際に
昔の情報を格納しているのがUNDOログです。
この2つを使ってデータを元に戻すことができます。

REDOログを使って過去のデータを最新の方向に進めることを
ロールフォワード」といいます。
逆にUNDO情報を使って変更を取り消す(昔の状態に戻す)ことを
ロールバック」といいます。

OracleにはSCN(システムチェンジナンバー」というものが存在しており、
Oracle内部の時間(正確には時間代わりの番号)を示します。

リカバリなどに使用するため、大切な機能です。

REDOのアーキテクチャ

データの更新はキャッシュ上で行われます。
その際、REDOログ(変更履歴データ)が生成されます。
この時点では、コミットがされておらず、それなのにブロックのデータが更新されます。

REDOログをコミットまでに必ずディスクに書き出しておくことで、
Oracleは持続性を実現します。

UNDOのアーキテクチャ

データを以前のものに戻すためのデータである
UNDO(ロールバックセグメント)についての解説です。

データが変更されるとUNDO情報が生成されます
UNDO情報はセグメントに格納され、この表領域をUNDO表領域といいます。
このUNDO表領域には複数のUNDOセグメントが作られます。
これは基本的に処理中のトランザクションとUNDOセグメントが1対1で対応するためです。

UNDOセグメントはリングバッファです。
リングバッファ…しばらくするとデータが上書きされてしまうバッファ
未コミットのデータは上書きされず、UNDOセグメントがいっぱいになり、UNDOセグメントは大きくなっていきます。

「undo_retention」というパラーメータなどでUNDO情報の保持時間を設定できます。
コミットされてもしばらくの間はUNDO情報を保持したいという場合に指定することがあります。

様々な状況におけるREDOとUNDO

ロールバック時の動作

Oracleでは未コミットでもデータはすでに変更済みになっています。
ロールバックが行われると、UNDO情報を使うことによってデータを元の値に変更します。

サーバープロセスが異常終了した時も、
PMONと呼ばれるバックグラウンドプロセスが定期的にチェックを行い、
サーバープロセスのクリーンナップを行ってくれます。

またSMONと呼ばれるバックグラウンドプロセスが、
データのトランザクション開始時の状態に戻してくれます、

読み取り一貫性に伴う動作

読み取り一貫性とは、検索処理に対して、ある時点のデータを見せる機能のことです。
たとえば、検索開始後に他セッションで変更されたデータは読ませず、
検索中はずっと検索開始時のデータを見せるようにするというものです。

この読み取り一貫性においてもUNDOが使われています。
読み取り一貫性はデータが更新されたタイミングを確認して、
検索開始後に変更されたデータの場合はUNDOを使用し、
過去のデータをメモリ上で再現します。

未コミットのデータを読む際の動作

Oracleはデフォルトでは「READ COMMITED」と呼ばれる動作をします。
これは、他セッションのコミット済みの変更データは読めるという特徴があります。
しかし、コミット前に他セッションの変更済みのデータを読めてはいけません。

この場合も、先ほどの読み取り一貫性と同様に過去のデータを見せます。
この動作も必要な時はUNDOを使用して、
過去のデータをメモリ上で再現することによって実現しています。

エラーが発生した場合の動作

ORA-1555」エラー
このエラーは「過去のデータを見に行ったが、必要な情報がない」ということを示しています。
多くの場合、長時間かかる検索でUNDO情報が上書きされていることが原因です。

例)24時間かかる検索の場合

検索を開始して1時間後に、別のセッションがあるデータを変更してコミットする
 ↓
数時間後に、そのデータに関するUNDO情報が上書きによって失われる
 ↓
検索開始から20時間後にデータが変更された箇所を読もうとする
 ↓
データが変更されているため、Oracleは検索開始当時のデータを再現しようとする
 ↓
しかし、UNDO情報が失われている
 ↓
検索ができず、ORA-1555エラーがでる。

このエラーが起きないようにするには
UNDO情報をより長く保持するよう設定することが考えられます。

チェックポイントの動作

チェックポイントとは、
メモリ上のデータへ同期させる作業のことです。
具体的にはDBWRがメモリからディスクにデータを書き出します。

REDOログと昔のデータがあればロールフォワードできるとはいえ、
あまり昔のデータからロールフォワードしようとすると時間がかかります。
そのため、チェックポイントによって定期的にデータをディスクに書き込み、
ロールフォワードにかかる時間を減らすようにしています。

インスタンスリカバリ時の動作

コンピュータはクラッシュすることがあり、この場合はOracleがデータ復旧をします。
REDOログをデータファイルに対して適用し、データを最新の状態に更新します。
ここで困ってしまうのが未コミットのデータの扱いです。

REDOログファイルには未コミットのREDOログも入っています。
しかし、最終的にコミットされなかったREDOログにはコミット情報がないため判別できます。
そのようなデータはUNDOを使ってロールバックされます。
きちんと原子性を守っています

UNDOの更新情報はREDOログに入っているため、
ロールフォワードすることによりUNDOも最新の状態になっていきます。
これは起動時に自動的行われますが、これをインスタンスリカバリと呼びます。
※クラッシュリカバリと呼びます。

まとめ

・REDOは古いデータを最新にするためにある
・UNDOは新しいデータを古くするためにある
・読み取り一貫性はUNDOを使っている
・マシンがクラッシュしたり、インスタンスが異常終了した場合には
 REDOとUNDOを使ってデータの復旧と未コミットデータのロールバックが行われる

所感

本日はREDOとUNDOについて学習を進めました。
データをとっておいたり、変更履歴が残っていたり
REDOとUNDOがあるから、安心してデータを預けたり取り出すことができますね。
実務についても忘れず活かしていこうと思います!
引き続き学習を進めていきます!

Discussion