1

私はしばらく探していましたが、これを見つけることができませんでした。私は Oracle を使用しており、次のような For ループがあります。

BEGIN
  FOR YEARIDs IN (SELECT DISTINCT YEARID From MyTable)
  LOOP
    UPDATE (
              SELECT    ......
            )
    SET     MyFlag = 1;
    COMMIT;  -- Added
  END LOOP;
END;

AutoCommit がオンになっていますが、FOR ループ全体が完了するまでコミットは行われないようです。したがって、上記のコードに Commit ステートメントを追加しました。これにより予期しない結果が生じるのでしょうか、それともベスト プラクティスに違反しますか? (つまり、AutoCommit がオンになっている場合、commit を明示的に呼び出してはいけませんか?)

ありがとう、スコット

編集: おっと... Oracle 11g と Oracle SQL Developer をクライアントとして使用しています。

編集: これまでのところ、ご回答いただきありがとうございます。クエリが実行されている時点で、データが生成および調整されています。他の接続がデータへのアクセスを試みてはなりません。なぜ頻繁にコミットするのかというと、開発中にデータのサブセットに対してクエリを実行すると、クエリは問題なく実行されます。テーブルには約 1,400 万件のレコードがあり、約 100k に対してテストしています。クエリはかなり複雑で、このサブセットに対して約 5 分で実行されます。テーブル全体に対して実行するように移動すると、クエリは 14 時間以上実行され、レコードの更新に失敗します。私の理論では、これほど多くの元に戻す情報を保持すると、開発サーバーで使用可能なすべてのリソースが消費される可能性があります。また、コミットを頻繁に行うと、元に戻す情報を解放して再利用できます。はい、遅いです。しかし、一晩中かかってもクエリが実際に完了する場合は、テスト サーバーに移動できます。(そして、パフォーマンス チューニングは後日行うことができます。) この締め切りはとうの昔に過ぎています。(締め切りに間に合わなかったので手伝いに連れてこられました。私の専門分野はオラクルではありません。)

4

2 に答える 2

7

ループ内でコミットすることは一般的に悪い考えです (ツールが自動的にコミットできるようにすることも同様です)。

ループ内でコミットすると、再起動可能なコードを書くことがはるかに難しくなります。3 回繰り返した後にエラーが発生した場合はどうなりますか? UPDATEこれで、2 つのステートメントの結果が正常にコミットされました。おそらく、更新された行を特定し、更新を元に戻すコードを記述するか、これら 2 つの成功した値のデータを更新しないようにするコードを追加する必要がありyearidます。それは確かに可能です。ただし、進行状況を追跡するために大量のコードを作成する必要があり、通常はコードがはるかに複雑になります。

ループ内でコミットすると、コードが大幅に遅くなります。コミットは一般に、かなりコストのかかる操作です。したがって、ループで実行することは一般的に悪い考えです。数十回のループ反復しかない場合は、それほど問題にはなりません。しかし、数百回または数千回の反復がある場合、コミットに大部分の時間を費やすことになります。

ループ内でコミットすると、ORA-01555 エラーが発生するリスクが大幅に高まります。に対するクエリMyTableには、データの一貫した読み取りビューが必要です。ただし、ループ内でコミットすると、セッションが古いUNDOデータを必要としないことを Oracle に伝えることになります。UNDO後続のループの繰り返しに必要なデータが Oracle によってパージされると、エラーが発生します。そして、N回の反復を成功させたが、どの年が処理されたのか、どの年が処理される必要があるのか​​ わからない、再開不可能なコードを扱うことに戻ります。

ループ内でコミットすると、データの一貫性の問題が発生する可能性があります。たとえば、他のセッションでレポートを実行している場合、それらのレポートで部分的に更新されたデータが簡単に表示されます。これは、多くの場合、データに一貫性がないことを意味します。3 年間のデータが変更され、他の年は変更されていない場合、レポートを理解することは非常に難しく、人 (またはプロセス) は簡単に誤った決定を下す可能性があります。

ループ内でコミットすると、コードの再利用性も低下します。コードにコミット (またはブロック内で確立したセーブポイント以外へのロールバック) が含まれている場合、そのトランザクションをまだコミットしたくない他のコードから呼び出すことはできません。これにより、人々はトランザクション制御なしでロジックを再実装しようとしたり、トランザクションの整合性を誤って侵害したりして、必然的にデータの一貫性の問題を引き起こすアプリケーションを構築するようになります。

于 2013-04-02T20:30:16.183 に答える
0

DBMS_PARALLEL_EXECUTE は素晴らしい機能の 1 つで、停止することなく mn の行を持つ大きなテーブルに使用してきました。

これにより、高可用性と再始動性が保証され、並列処理が利用されます。

これを参照して ください https://oracle-base.com/articles/11g/dbms_parallel_execute_11gR2

定期的な間隔(行サイズに応じて1000〜10000行など)の後にデータをコミットしても問題はありません。実際、大規模なデータ移行/バックスイープの場合、「ORA-01555 スナップショットが古すぎます」を回避するために、チャンクしてコミットすることをお勧めします。

これにより、ベース テーブルでの長時間のロックも防止されます。

他の人がコメントしたように、「AutoCommit」はここでは不要です...

于 2016-10-16T22:37:28.333 に答える