- PR -

コミット間隔

投稿者投稿内容
KI
大ベテラン
会議室デビュー日: 2007/01/10
投稿数: 239
投稿日時: 2007-05-20 01:33
引用:

しかし、OracleTransactionの別オブジェクトを生成すれば(trnではなく、trn1とか)
実行時に「並列トランザクションはサポートされていません。」
となります。



仮に変数名を trn1 に変えたとして
コード:
Try 
ループ処理(CSVの全レコードを抽出するまで) 
{
    cmd.ExecuteNonQuery()
    cnt = cnt + 1
    If cnt = 100 then
        trn.Commit()
        Dim trn1 As OracleTransaction = cnn.BeginTransaction
        cmd.Transaction = trn1
    End If 
}


となりますが、このあたりの構造に問題があります。
「trn.Commit()」の行でコミットしているトランザクションは、
ループの外で宣言したトランザクション(trn)であって、trn1 ではありません。
ですから、trn1 はどこでもコミットされないことになります。
ですから、101レコード目の処理で、(trn1 がコミットされないまま)
新しいトランザクションを開始しようとしてエラーになっているものと思われます。

ループの外でトランザクションを開始するのをやめて、
以下のような構造にしたほうが、見やすいし、間違いがないと思います。

コード:

Dim trn As OracleTransaction

Try
    Dim cnt As Integer = 0
    For ☆ループ条件☆
        'カウンタが0ならトランザクション開始
        If cnt = 0 Then
            trn = cnn.BeginTransaction()
            cmd.Transaction = trn
        End If

        cmd.ExecuteNonQuery()

        If cnt = 100 then
            '100件に達したらコミットしてカウンタを0に戻す
            trn.Commit()
            trn = Nothing
            cnt = 0
        Else
            '100件に達していない場合はカウントアップ
            cnt = cnt + 1
        End If 
    Next

    '残りのレコードをコミット
    If Not trn Is Nothing Then
        trn.Commit()
    End If

Catch ex As Exception
    If Not trn Is Nothing Then
        trn.Rollback()
    End If
Finally
    cnn.Close()
End Try



未検証なので、細かいミスあったらすみません。
未記入
常連さん
会議室デビュー日: 2007/05/01
投稿数: 35
投稿日時: 2007-05-20 11:49
KIさん、ご回答ありがとうございます。

大変分かりやすい、サンプルコードを御提示いただきありがとうございます。
コミット間隔制御が実現できました。

本当にありがとうございました。
また何かありましたらお願い致します。

よっしー
大ベテラン
会議室デビュー日: 2007/05/17
投稿数: 143
投稿日時: 2007-05-20 11:54
> じゃんぬねっとさん、ご質問ありがとうございます。
> 一定間隔にしたい理由は、性能問題です。
> CSVのレコード件数が10万件存在するとした場合、
> 1レコード読み取り→SQL→コミット
> のサイクルを10万回繰り返すのではなく、
> 1レコード読み取り→SQLを100回繰り返し、1回コミット
> のサイクルを1000回繰り返したほうが性能がよいと考えられるからです。
> (実際試したわけではないので、保証はできませんが。。。)

じゃんぬねっとさんが言いたいのは、10万件繰り返し→1回コミット
ということなのでは?
10万件繰り返ししないで1回で10万件更新できればもっと良いですが。
未記入
常連さん
会議室デビュー日: 2007/05/01
投稿数: 35
投稿日時: 2007-05-20 12:10
よっしーさん、ご指摘ありがとうございます。

10万件繰り返し→1回コミットでしたか。。。
それはこのスレッドを立てる前に実現できていました。

そもそも
・1レコード読み取り→SQL→コミットを10万回繰り返す
・1レコード読み取り→SQLを10万回繰り返し、最後に一発コミット
上記の2点はスレッドを立てる前に実装でき、検証もできていました。
しかし性能を向上させるためには、コミット間隔を50〜100件にするのが
自明の理だと思っていましたので、その実装方法がわからず、スレッドを
たてさせていただきました。

よろしくお願い致します。
マーサ
ベテラン
会議室デビュー日: 2004/11/26
投稿数: 87
投稿日時: 2007-05-21 11:25
引用:

未記入さんの書き込み (2007-05-19 19:23) より:

ループ処理の中の
Dim trn As OracleTransaction = cnn.BeginTransactionでコンパイルエラーです。
あたりまえか。。。


そこは単純に変数の2重定義ですよね?
#そういうエラー内容になっていると思いますが。。。

引用:

BeginTransaction -> Commitを繰り返したいのではありません。
BeginTransactionを実行し、その後のSQL処理を繰り返し、
100回単位でCommitを行いたいのです。
CSVのレコード件数が250件存在し、230件目に不整合なデータが存在する場合、
データベースには1件〜200件のデータが出力され、201〜250件目のデータは
出力されないイメージです。


100件単位での登録で、エラーになった部分のデータを破棄するとか、ちょっと理解出来ませんが。
正常なデータも捨ててしまうのですか?

引用:

一定間隔にしたい理由は、性能問題です。
CSVのレコード件数が10万件存在するとした場合、
1レコード読み取り→SQL→コミット
のサイクルを10万回繰り返すのではなく、
1レコード読み取り→SQLを100回繰り返し、1回コミット
のサイクルを1000回繰り返したほうが性能がよいと考えられるからです。
(実際試したわけではないので、保証はできませんが。。。)


コミット実行には結構コストがかかりますよ。
つまり、コミット回数が増えれば増えるだけ、コストが増大します。


[追記]
高速で登録を行いたいと言うのであれば、SQL*Loaderを使う手もありますが。

[ メッセージ編集済み 編集者: マーサ 編集日時 2007-05-21 11:41 ]
未記入
常連さん
会議室デビュー日: 2007/05/14
投稿数: 26
投稿日時: 2007-05-21 12:36
引用:


BeginTransaction -> Commitを繰り返したいのではありません。
BeginTransactionを実行し、その後のSQL処理を繰り返し、
100回単位でCommitを行いたいのです。
CSVのレコード件数が250件存在し、230件目に不整合なデータが存在する場合、
データベースには1件〜200件のデータが出力され、201〜250件目のデータは
出力されないイメージです。
よろしくお願い致します。



これもし500件の時はどうなるんですか?
1〜200は同じとして、201〜300が出力されないまではわかります。
ではその後は?
301〜は処理するんですか?
それともエラー出た時点で処理が止まって、301〜500も全て出力しないんですか?
どういったデータなのかわかりませんが、一つエラーがあっただけで
他の正常に登録できるであろうデータを切り捨てるというのはどうなんでしょう。
100件単位にすれば、100件のうち1件でもエラーあれば最低99件が無駄に。
1000件単位にすれば999件が無駄に。
10件単位だと9件が無駄に。
分ける単位によって無駄が増減するのも仕様としてどうなのかなと。
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2007-05-21 13:37
引用:

未記入さんの書き込み (2007-05-20 12:10) より:
しかし性能を向上させるためには、コミット間隔を50〜100件にするのが
自明の理だと思っていましたので、その実装方法がわからず、スレッドを
たてさせていただきました。


その自明の部分を掘り下げてみたら?と言いたいのだと思いますよ。

数百件おきにコミットを行うのは速度上の問題というよりは、HDD容量の問題で行われていた実装です。100万レコードを一度にコミットするためには100万レコードを格納するための大きなロールバックセグメントが必要になります。HDDが高価な時代、大容量のロールバックセグメントを用意するなんて出来なかったんですよ。

HDDが安価な現代においては、巨大なロールバックセグメントを用意するという選択もあるはずです。コミットを一度ですませば「トランザクション分離」とか「ロールバック処理」、「読み取り一貫性」などの恩恵も受けられます。
よっしー
大ベテラン
会議室デビュー日: 2007/05/17
投稿数: 143
投稿日時: 2007-05-21 14:00
もしかして、要件的にトランザクション管理がいらないのでは?

BeginTransactionしなければ良いのでは?

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