[DB] Oracle VS DB2

■インスタンスとデータベース
オブジェクトの論理的なまとまり表す共通概念。

Oracle
 1つのインスタンスには1つのデータベースが対応する。
 
 アプリ開発等で、
 複数のユーザに対して個別の環境を提供する際、
 スキーマを最小単位として分散環境を提供する場合がある。
 ただし、
 スキーマの単位では、
 データベースの構成に関する個別の設定などの明確な分離は不可。

DB2
 1つのインスタンスには複数のデータベースを対応させられる。
 
 データは管理する為のオブジェクト(テーブルや索引など)の集合で、
 アプリ接続、データ更新、バックアップ/リカバリなどの障害回復の基本単位になる。
 
DB2のデータベース単位による分割は、
Oracleのスキーマ単位による環境分散に比べ、
より独立した環境をユーザに提供できる。

OracleDB2も1つのサーバ上に複数のインスタンスを作成できるが、
複数インスタンスには、
・追加のシステムリソース(メモリとディスクスペース)が必要になる
・複数インスタンスを管理するための負荷が増大する
等のデメリットがある。

DB2の1インスタンスの中での複数データベース化には、
・このような複数インスタンス化によるデメリット低減
・独立したデータベース環境の提供
という利点がある。


■トランザクションとデータの一貫性
トランザクション=1つ以上のSQL文を含む作業単位
トランザクションの最終結果が成功か失敗の一方のみ(アトミック)
というのが基本的な考え方。
そのデータの一貫性を保証するための仕組みに相違がある。

Oracle
 ロールバック・セグメントによるマルチバージョン制御を使用。
 
 あるアプリが更新トランザクションを開始すると
 データの旧バージョンはロールバック・セグメントに保持される。
 他アプリがそのデータに対する読み取り要求をすると、
 ロールバック・セグメントに保持された旧バージョンのデータを取り出す。
 更新トランザクションがコミットされると、
 ロールバック・セグメントのバージョンは消去され、
 他の全アプリはテーブル上の新バージョンのデータを見る。

DB2
 ロッキングメカニズムを使用。
 
 ロールバック・セグメントに当たるものはなく、
 データの読み取り一貫性の保証には、
 ロッキング・メカニズムを使用。
 あるアプリが更新トランザクションを開始すると、
 テーブル内の該当するデータには非共有モードのロックが保持される。
 他のアプリがそのデータに対する読み取り要求をすると、
 未コミット読み取り分離レベル(ゆわゆるダーティリードを許可するレベル)以外の
 読み取りトランザクションでは、
 データを取り出すことは許可されず、待たされる。
 更新トランザクションがコミットされると、
 非共有モードのロックが解除され、
 他の全てのアプリがテーブル上の新バージョンのデータを見れる。
 
同一表に同時にアクセスするトランザクションを持つDB2アプリの場合、
ロック待機待ち時間が長くなり、性能が落ちる。
→DB2でのアプリ開発では、
 ロック待機待ちを減らす為に、
 ・読み取りトランザクションを定期的にコミットする
 ・オプティミスティック・ロック方式を使用する
 なりしてアプリ並行性の改善を考えること。


■オプティマイザ
Oracleのオプティマイザは、
ルール・ベース(15段階のアクセス・パスのランク基準)とコスト・ベース(各表の統計情報基準)の2種類を提供。
DB2のオプティマイザは、
常にコスト・ベース(各表の統計情報基準)でアクセス・プランが選択される。

コスト・ベースのオプティマイザは、
SQL文がアクセスするデータベース・オブジェクトについて、
使用可能なアクセス・パスを検討し、
統計に基づいた情報要素を考慮して、
最速の実行計画を判断する。


■分離レベル
DB2:
ANSI/ISO標準のトランザクション分離レベルを全てサポート
-デフォルトトランザクション分離レベル:Read Committed
Oracle
Read Committed, Serializableのみサポート
-デフォルトトランザクション分離レベル:Read Committed

ANSI/ISO標準トランザクション分離レベル
Uncommitted Read (未コミット読み取り)
Read Committed (コミット読み取り)
 コミットされたデータのみ参照を許すことでデータの一貫性を保証する。
Repeatable Read (繰返し可能読み取り)
Serializable (直列可能)

■Read Committed
トランザクションの制御の実装が異なるために、
Read Committedレベルの振る舞いも異なる。
特に、更新中のデータに対する検索を行った場合の挙動。

@DB2
検索時に共有ロックをかける。
読み取るデータが他プロセスで更新中の場合は、
既にそのデータに排他ロックがかかっているため、
共有ロックをかけられない。
→更新中のデータに読み手はアクセス出来ず、検索処理が待たされる。
⇒更新中のデータが確定されるまで検索処理が待たされる振る舞いは、
 複数アプリ間の同時実行性を損なわす。
 →[未コミット読み取り]でダーティ・リードを許す方法がある。
  が、実用的でない。

@Oracle
マルチ・バージョン一貫性制御で、
UNDO表領域に保持された更新前の情報を読み込むため、
読み取るデータ更新中でも、検索処理が待たされることはない。
→更新中のデータの更新前のデータにも読み手はアクセス出来る。


■DB2で優れた同時実行性を実現する方法
ポイント:
ロック取得時間(他トランザクションからの更新を許さない時間)を短くするような排他制御のアプリ設計をすること。

ロック取得時間が短ければ、
検索処理と重複する機会を減らせる。
→オプティミスティック・ロック(楽観的ロック)が代表的な実装方法

□Optimistic Lock
プログラミング例@クライアントサーバシステム
1.ロックを取得せずにデータを読み込む。
2.読み込んだデータをアプリ上(画面上)で変更
3.UPDATE実行のタイミングで、ロックをかけて再度データを読み込む。
4.データベース上でデータ変更の有無を列データの更新時間などで確認する。
5.他ユーザによってデータが変更されていなければ、コミットし、更新を確定する。
 他ユーザによってデータが変更されていれば、ロールバック処理を行う。
 アプリケーション上での変更データは破棄して、ユーザに再入力を促す。

ただし、
optimistic lockは、
頻繁に複数ユーザが同時に同一データを変更するシステムだと、
更新に失敗し、ユーザに再入力促す確率が高くなるため、
利便性が下がる場合あり。
その場合は、
1回目の読み込み時でロックをかける設計にすべき。
加えて、
データにロックをかけて画面表示するような場合は、
画面を表示したまま放置することがないよう、
一定時間内に画面上から入力がなければ、取り込んだデータを自動破棄する設計にすべき。

つまり、
DB2の場合、
optimistic lockによる実装が並行性の改善には有効だが、
optimistic lockによる画一的な設定でよいわけでない。
アプリの要件やユーザの利便性を満たす排他制御方法を選択すべき。


■ロックの制御
@Oracle : リードロックは取得しない。
 
 更新を前提としたデータの読み取りを行う場合は、
 ユーザが明示的に行ロックを取得する為に、FOR UPDATE句を使う。
 →トランザクション終了まで検索結果にロックをかけ、
  他トランザクションからの更新を防ぐ。
 ex. SELECT * FROM TBL FOR UPDATE

@DB2 : システム側で常にリードロックを取得する。
 
 ※デフォルトでは、ロックがかかるタイミングはカーソルが行の上にある間。
 デフォルトのリードロックだけでは他のトランザクションからの更新を十分には防げない。
 で、
 分離レベル[繰返し可能読み取り]OR[直列可能]レベルに変更する必要がある。
 →検索結果には、COMMIT/ROLLBACKまでロックをかけ、
  他トランザクションの更新を防げる。

 排他制御が必要な場面で、その都度、
 個々のSQL分にWITH句を用いて分離レベルを指定する。
 ex. SELECT * FROM TBALE FOR UPDATE WITH RS


■ロック待機への対処
@Oracle
 *NOWAITオプション
  SELECT HOGEHOGE FOR UPDATE + NOWAIT
  →ロック待機せずに、すぐに制御を戻す。
  
  1 TXN1がレコードAを検索→レコードAをロック
  2 TXN2がレコードAを検索
   →レコードAがロックされているため、
    待機せずに制御が戻る。
 
@DB2
 *LOCKTIMEOUT(秒単位)パラメータ
  →ロック待機時間がLOCKTIMEOUTに達した場合、
   ロック待機しているトランザクションがロールバックされる。
   デフォルト:-1(永遠に待つ。。)
  
  1 TXN1がレコードAを検索→レコードAをロック
  2 TXN2がレコードAを検索
   →LOCKTIMEOUTで指定された時間(秒)待機する。
  
  [DB2#LOCKTIMEOUT=0] = [Oracle#NOWAIT]
  
  LOCKTIMEOUTは、データベース単位の設定。
  →全てのトランザクションに一律に影響する!
  ex. db2 UPDATE DB CFG FOR dbname USING LOCKTIMEOUT 10
  
  タイムアウト発生時、
  リトライで、エラーになった処理が問題なく実行される場合は、
  リターンコードを利用して、
  アプリにリトライロジックを組み込む方法もある。
  その場合、
  トランザクションがDBマネージャによってロールバックされないよう、
  レジストリ変数で[DB2LOCK_TO_RB=STATEMENT]指定しておくこと。
  ちなみに、
  DBマネージャによってロールバックされた場合のリターンコードは、
  [SQL0911N]
  だが、STATEMENT指定してると、
  [SQL0913N]
  が返される。


■ロック・エスカレーション@DB2
1つのアプリが多量の行ロックでロック用メモリ領域を占有する
のを防ごうとする動きで、一種の縮退運転の機能。
多数の行ロックを1つの表ロックに代えてロックの量を一挙に減らす。

ロック用メモリ領域の大きさは、
LOCKLIST(データベース構成パラメータ)によって決定する。
この領域の上限を超えるか、
単一アプリがMAXLOCKS(データベース構成パラメータ)以上の割合でLOCKLISTを使用する場合に、
ロックエスカレーションが発生する。

*LOCKLIST
 ロックの管理に使用されるメモリ領域

*MAXLOCKS(%)
 単一アプリによって使用さえるロックメモリ領域の比率

ロック・エスカレーションは、アプリの並行性に影響する。
ex
ロックエスカレーションの発生で
ある表の共有ロックを保持した場合、
他のアプリはその表内の行の更新が出来なくなる!
同様に、
アプリが表の排他ロックを保持した場合、
他のアプリはその表内の行の読み取りや更新が出来ない!

→通常DB2のアプリ設計としては、
 ロック・エスカレーションを発生させないように
 LOCKLISTとMAXLOCKSのパラメータをチューニングする。

 チューニングする際には、
 その使用環境でどれだけLOCKLISTが使われているか
 をモニタリングし、最適値を導出する。


ref:
OracleとDB2、アーキテクチャはこれだけ違う (★★★☆☆)
http://www.atmarkit.co.jp/fdb/rensai/rdbmsarc02/rdbmsarc02_1.html
OracleとDB2、ロッキング・メカニズムはこれだけ違う (★★★★☆)
http://www.atmarkit.co.jp/fdb/rensai/rdbmsarc04/rdbmsarc04_1.html

tag : Oracle DB2 ANSI ISO Read Committed Serializable Uncommitted Repeatable

2009-04-09 23:15 : 開発 : コメント : 0 : トラックバック : 0 :
コメントの投稿
非公開コメント

« next  ホーム  prev »

search

ad



counter


tag cloud

category cloud