- PR -

DBのダーティーリードの対策について

投稿者投稿内容
matu
ベテラン
会議室デビュー日: 2002/09/01
投稿数: 95
お住まい・勤務地: 東京
投稿日時: 2004-03-21 20:20
 javaとは少し観点が違うのですが、データベースフォーラムが無い為
こちらに書かせて頂きました。すみません。
(なぜデータベースのフォーラムは存在しないのでしょうか??)


 データベースのダーティーリードの対策として以下の様なケースには
どの様な策を取れば良いでしょうか?
状況1:データを読む処理Xとデータを更新/追加する処理Yがあります
状況2:処理Yはバッチ処理で50万件近いデータを更新します
状況3:ロールバックセグメントが小さい為、対策として10万件単位で
    コミットを発行してしまっています。
 この様な場合、処理Xのダーティーリードを防ぐ(例えば20万件で中途
 半端にサマライズなどを行わない為)にはどの様にするのがベストで
 しょうか?

 つまり言葉を変えると、コミットをまたいで排他制御を行う事はデータ
ベース側の設定や処理で可能でしょうか?アプリケーション側でフラグ等
を使わないと実現できないでしょうか?


 Oracleを例に色々と本やマニュアルに目を通してみたのですが例えば
1、読み取り専用トランザクション/読み書き専用トランザクションだと?
  (SET TRANZACTION READ ONLY | SET TRANZACTION READ WRITE)
  これは処理Yが10万件を処理してコミットした後では意味が無い?
2、isolationレベルを調整?
  (SET TRANZACTION ISOLATION LEVEL SERIALIZABLE)
  結局これもコミットをした後では意味が無い?
3、明示的なテーブルロックを使用する?(2相ロックの使用?)
  (LOCK TABLE xxx IN ??? MODE)
  これも有効な気がするのですがOracleのマニュアルを読んだところ
  MODEがEXCLUSIVEでも読み取りは可能になってしまう為、ダーティ
  リードは発生してしまいます。よってNGでしょうか?またこれも
  コミットをまたいでロックはできないでしょうか??


 長々とすみませんが、何かお気づきの点がありましたらご教授ください。
よろしくお願いします。


 ちなみに処理Xがダーティーリードを検地できた場合は
A、処理Yが短期的(数秒)バッチ処理の場合は処理XをWAITさせる
B、処理Yが中長期的(数分以上)バッチ処理の場合は処理Xで例外を発生
  させMMI側で対策を取る
 とできればと考えています。

p.s.
 すみません。よく考えたらコミット後の中途半端なデータを読む事を考えて
いるので「ダーティーリード」という表現はふさわしくないかもしれませんね。



[ メッセージ編集済み 編集者: matu 編集日時 2004-03-22 12:30 ]
永井和彦
ぬし
会議室デビュー日: 2002/07/03
投稿数: 276
お住まい・勤務地: 東京都
投稿日時: 2004-03-21 23:19
引用:

matuさんの書き込み (2004-03-21 20:20) より:

 データベースのダーティーリードの対策として以下の様なケースには
どの様な策を取れば良いでしょうか?
状況1:データを読む処理Xとデータを更新/追加する処理Yがあります
状況2:処理Yはバッチ処理で50万件近いデータを更新します
状況3:ロールバックセグメントが小さい為、対策として10万件単位で
    コミットを発行してしまっています。
 この様な場合、処理Xのダーティーリードを防ぐ(例えば20万件で中途
 半端にサマライズなどを行わない為)にはどの様にするのがベストで
 しょうか?



永井です。

私ならDB上にフラグを作って、それで制御しますね。理由は「競合を起こし得る全ての要素から共有されている資源」だからです。制御も比較的すっきりしますし。

このようなケースの場合、具体的には実行状況管理用のテーブルを作成します。
それぞれ管理したい区分に関してデータを作成しておいて、例えば短期的バッチであればSELECT FLG ... FOR UPDATE(で、もしFLGの値として1を取得したらAbort)、中長期バッチであれば初期処理としてUPDATE ... SET FLG=1 ...でCOMMITしておいてからバッチの本体のトランザクションを走らせるといったことをします。
#当然、中長期バッチの最後でこのフラグは落します。

この下準備をした状態で、処理Xに短期バッチと同様なSELECT FLG ... FOR UPDATE処理(Abortに関しても同様)をさせれば大丈夫だと思います。

<余談>
上の具体例はちょっとカスタマイズした状態ですので、本当にそれで大丈夫かはマトリックスとか作って検討してみて下さい。縦軸に「先行で走っているもの(実行中)」、横軸に「後追いで起動されたもの」を取って、「×(Abortする)」「△(待つ)」「○(並行で実行出来る)」等として、関係者間で合意を取っておくのがお勧めです。
#で、実装がそれを全て満たすか、順番に確かめる、と。
</余談>


[ メッセージ編集済み 編集者: 永井和彦 編集日時 2004-03-22 01:16 ]
Cluster
ぬし
会議室デビュー日: 2003/03/06
投稿数: 289
お住まい・勤務地: 大阪
投稿日時: 2004-03-22 00:53
私なら・・・、DB以外のところで制御します。


  1. 処理Xがオンライン処理なら、処理Yが終わるまで利用できないように制御する。
  2. 処理Xがバッチ処理なら、ジョブ管理ソフト(H社のJP1とか)で、処理Yが
     正常終了するまで実行されないようにする。


みたいなことを考えますが・・・。
投稿の意図からずれてますかね?
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2004-03-22 01:12
参考程度に・・・的を得てない発言かもしれませんが・・・

現在私の行っているプロジェクトでも長時間のバッチがあるのですが、

1・排他管理オブジェクトに処理中通知を行う(更新系の制御用)
2・バッチ用のワークテーブルにデータを退避
3・バッチ処理をワークテーブルに対して行う
4・処理完了(数十分)
5・排他管理オブジェクトに処理中通知を行う(検索系の制御用)
6・テーブル差し替え(元テーブルを消して、ワークから移行)
7・テーブル差し替え完了
8・排他管理オブジェクトに処理完了通知を行う

という感じになっています。
そして、DBを操作する時には、必ず排他管理オブジェクトに対して
処理中確認を行うようにしています。
開発のポリシーとしては、極力検索系の処理を待たせないようにしています。
もっとスマートなやり方があると思うのですが・・・
matu
ベテラン
会議室デビュー日: 2002/09/01
投稿数: 95
お住まい・勤務地: 東京
投稿日時: 2004-03-22 02:38
 永井さん、Clusterさん、かつのりさんこんばんは。
 皆さんのご意見とても参考になります。また皆さんの意見も一致していて
だいぶ私の心もベクトルが処理に向いてきました。そもそもデータベース側
ではできないのかも・・・?
 あとは皆様の回答を読んでいて少し気づいたのですが、短期的バッチにつ
いてはもう少しロールバックのエリアの見直しも検討してみたいと思います。
永井さんから教わったSELECT ... FOR UPDATEが少しわからなかったので
すが、目がくっつきそうなので明日じっくり理解してみたいと思います。
なんとなく排他制御が簡単にできそうな気がして魅力的です

引用:

かつのりさんの書き込み (2004-03-22 01:12) より:

1・排他管理オブジェクトに処理中通知を行う(更新系の制御用)
8・排他管理オブジェクトに処理完了通知を行う



 1と8の排他管理オブジェクトはjavaで言うとクラスのインスタンス
ですか?それともデータベースでしょうか?
 あまり大きなデータでは無いのでどちらで行ってもメモリからのリード
かとは思うのですがどの様にしているのかな?と少し気になりました。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2004-03-22 23:18
matuさん、こんばんは。

排他管理オブジェクトですが、現状のPJではDBに排他状態を書き込んでます。
ただし、アベンドした場合に自動で排他解除できないため、
アベンド時になんらかの排他解除方法を実装する必要が出てきて、
各業務ロジックで排他制御に振り回されることになりやすいです。

ですので、Javaのインスタンスで排他管理を行うのをお勧めします。
きめ細かい処理もやりやすいですし。

#今のPJの排他管理システムはダメダメなんで・・・
#でも共通部品なんでいじれない・・・
はにまる
ぬし
会議室デビュー日: 2003/12/19
投稿数: 969
お住まい・勤務地: 誤字脱字の国
投稿日時: 2004-03-23 09:24
はにまるです。

 もし言語を使っているのであれば、

 1.排他制御用部品
 2.それぞれの処理

 の2つを用意します。
 2は、それぞれXとYの事で、
 1は、皆様が仰っている排他の事ですが、

 1は、2と同一プロセス稼動させる部品で、
 内部で別トランザクションを稼動させ、
 制御テーブルをロックします。
 # データ更新しない所がミソ。

 1の部品で「制御テーブルがロック済み」の状態を返した場合、
 X及びYの再実行の状態にします。

 1の内部では、ロックをしているだけですので、障害時には勝手にロックが外れ、
 再実行対策になります。
 ただし、X及びYの処理自体がハングした場合の障害では、
 Oracleの自動ロック解除は時間が掛る事があるので注意が必要です。
 (個人的に知っているのは、kill sessionせずに最大1時間弱かかった...)

と言いつつも、あまりお奨めはしないかな?(私には複雑だから ^^;)

 ロールバックセグメントですが、
 私は「領域制限無し」&「一定量増加時は、規定値まで自動縮小させる」
 パラメータを利用します。
 この際、ハードディクスの領域問題に発展する為、
 ハードディスクの閾値監視は行っておいた方が良いと思います。

以上
matu
ベテラン
会議室デビュー日: 2002/09/01
投稿数: 95
お住まい・勤務地: 東京
投稿日時: 2004-03-23 10:34
 かつのりさん、はにまるさんおはようございます。

引用:

かつのりさんの書き込み (2004-03-22 23:18) より:

ですので、Javaのインスタンスで排他管理を行うのをお勧めします。
きめ細かい処理もやりやすいですし。


引用:

はにまるさんの書き込み (2004-03-23 09:24) より:

 1は、2と同一プロセス稼動させる部品で、
 内部で別トランザクションを稼動させ、
 制御テーブルをロックします。
 # データ更新しない所がミソ。

 1の部品で「制御テーブルがロック済み」の状態を返した場合、
 X及びYの再実行の状態にします。

 1の内部では、ロックをしているだけですので、障害時には勝手にロックが外れ、
 再実行対策になります。



 ありがとうございます。とても参考になります。かつのりさんに教えて頂いた
様に処理(裏はDB)での排他を考えているのですが、「CMP」EJBを使おうかと
考えています。
 現在は
処理X:「セッションEJB」で、JDBCを使いデータベースのサマライズ/リスティング
処理Y:「セッションEJB」で、JDBCを使い数十万件のデータベース更新
 となっています。
 ここで処理X、処理Yともにトランザクション属性=Requiredで処理の先頭で「CMP」
EJBを使用する(CMPも勿論Requiredです)事により制御のシリアライズが保たれます
でしょうか?
 間違っていないか不安です・・

 ちなみに処理Yが短期的なバッチの場合は良いのですが長期的なバッチの場合は
例外をスローする様にしたいのですが「待ち」状態にさせない様にするにはどの様
にすれば良いでしょうか?

※そもそも本当は数十万件の更新処理を昼間にやるのを止めたいのですが・・


引用:

 ただし、X及びYの処理自体がハングした場合の障害では、
 Oracleの自動ロック解除は時間が掛る事があるので注意が必要です。
 (個人的に知っているのは、kill sessionせずに最大1時間弱かかった...)

と言いつつも、あまりお奨めはしないかな?(私には複雑だから ^^;)

 ロールバックセグメントですが、
 私は「領域制限無し」&「一定量増加時は、規定値まで自動縮小させる」
 パラメータを利用します。
 この際、ハードディクスの領域問題に発展する為、
 ハードディスクの閾値監視は行っておいた方が良いと思います。


 ロールバックセグメントのチューニングはまだした事が無いので調べてみます。
 特に「一定量増加時は、規定値まで自動縮小させる」が初めて聞く言葉なので。

 ちなみに関係無いのですが最近300万件のデータベースのサマライズSQLが不調で
SGAのチューニングを行ったのですが、全然バッファヒット率がアップしませんでした。
データベースフォーラムも欲しいです・・


 色々ご指導いただき、ありがとうございます。


[ メッセージ編集済み 編集者: matu 編集日時 2004-03-23 10:40 ]

スキルアップ/キャリアアップ(JOB@IT)