2017-02-22 15 views
0

私は現在、以下の2つの表1と表2の構造を持っています。あなたが見ることができるように表1は、列FKのために複数の行が含まれており、FKの列には、表1SQLカーソルのパフォーマンス/代替?

にID列順表1から最新の値をIDごとに1つだけの行を持つ表2 ID列への外部キーになります
Table 1  
ID FK END_DTTM 
1 1 01/01/2000 
2 1 01/01/2005 
3 1 01/01/2012 
4 1 01/01/2100 
5 2 01/01/1999 
6 2 01/01/2100 
7 3 01/01/2100 

Table 2 
ID END_DTTM 
1 01/01/2100 
2 01/01/2100 
3 01/01/2100 

ビジネス上の要件は、表2のすべての更新を追跡して特定時点のデータを取得できるようにすることです。これを達成するために、SQL 2016とTemporalテーブルを使用しています。ここでは、Table 2のすべての更新で履歴テーブルにバージョンが自動的に作成されます。

は、私は現在、ひどく遅いカーソルを使用していますが、約30分で71000行を処理している、挿入、更新プロセスを達成するために、テーブルの周り60millionの行を持っています!次のようにクエリをカーソル:実際にはカーソルそのものよりも遅くTADた、

BEGIN 
BEGIN TRY 
BEGIN TRANSACTION; 
Declare @ID as int; 
Declare @FK as int; 
Declare @END_DTTM as datetime2; 



DECLARE @SelectCursor as CURSOR; 

SET @SelectCursor = CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY FOR 
SELECT [ID],[FK],[END_DTTM] from TABLE1 order by FK,ID; 

OPEN @SelectCursor ; 
FETCH NEXT FROM @SelectCursor INTO @ID,@FK,@END_DTTM; 

WHILE @@FETCH_STATUS = 0 
BEGIN 


UPDATE TABLE2 
set 
END_DTTM = @END_DTTM 
where ID = @FK 

    IF @@ROWCOUNT = 0 
BEGIN 
    INSERT Table2 
    (
ID,END_DTTM 
) 
    VALUES (

    @FK,@END_DTTM 

) 
    END 

FETCH NEXT FROM @SelectCursor INTO @ID,@FK,@END_DTTM; 
END 

CLOSE @SelectCursor; 
DEALLOCATE @SelectCursor; 
    COMMIT TRANSACTION; 
    END TRY 
BEGIN CATCH 
    IF @@TRANCOUNT > 0 
    ROLLBACK TRANSACTION; 

    DECLARE @ErrorNumber INT = ERROR_NUMBER(); 
    DECLARE @ErrorLine INT = ERROR_LINE(); 
    DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(); 
    DECLARE @ErrorSeverity INT = ERROR_SEVERITY(); 
    DECLARE @ErrorState INT = ERROR_STATE(); 

    PRINT 'Actual error number: ' + CAST(@ErrorNumber AS VARCHAR(10)); 
    PRINT 'Actual line number: ' + CAST(@ErrorLine AS VARCHAR(10)); 
    PRINT 'Actual message: ' + CAST(@ErrorMessage AS VARCHAR(4000)); 
    PRINT 'Actual severity: ' + CAST(@ErrorSeverity AS VARCHAR(10)); 
    PRINT 'Actual state: ' + CAST(@ErrorState AS VARCHAR(10)); 
    Insert into ERROR_LOG 
    (
    SOURCE_PRIMARY_KEY 
    ,ERROR_CODE 
    ,ERROR_COLUMN 
    ,ERROR_DESCRIPTION 
    ) 
    VALUES 
    (
    null, 
    @ErrorNumber, 
    @ErrorState, 
    @ErrorMessage, 
    'Error!' 
    ); 
    Throw; 
    -- RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState); 
    END CATCH 
END; 

私は、CTEを使用してみましたが、私はそれでどんなパフォーマンスの向上を見ていません。

上記のテーブルベースの操作を使用して、テーブル1と更新2のすべての行を処理し、一時テーブルが更新を取得して変更を追跡できるようにするには、より良い方法がありますか?

+1

あなたがしようとしているロジックが何であるか説明してください。見知らぬ人がカーソルコードを見つけようとしないでください。 –

+0

ゴードン、私はすでに私のポストで論理を説明しようとしました。このコードは、私がやっていることを示すもので、役に立たないと無視できるものです。私が明確でない場合は、そう言いましょう。私は、例やコードなしでそれを言い換えようとすることができます! – user3363391

+0

希望の結果を表示します。 –

答えて

0

ああ、すべてあなたがしたいということですか?

insert into table2(ID, END_DTTM) 
    select fk, max(END_DTTM) 
    from table1 t1 
    group by fk; 
+0

実際にはテーブルに最新の/ fkレコードを挿入するのではなく、最初に挿入するレコードとそれに続くもの一時テーブルが変更追跡を記録するように更新されました。また、私はテーブルに他のフィールドがあり、挿入または更新する必要があるので、maxは解決策ではないかもしれません。 – user3363391

+0

「バージョン」をテーブル2にトリガで挿入するだけの理由はありますか? 5分ごとに更新クエリを簡単に実行しているようです。 – Doug

1

私はあなたが更新SQLを実行しているかどうかはわかりませんが、私は、私は、Oracleの変化を追跡するために使用するプロセスを説明します。

私のセットアップ私が監査するテーブルの上にトリガ。同じ列を持つ別のテーブルを作成します.1つはOLD_で始まり、もう1つはNEW_で始まります。 Oracleトリガでは、新しい行と古い行を参照できます。古い値と新しい値、DMLアクションタイプ、およびTIMESTAMPを使用して監査テーブルに挿入します。さらに、データベースユーザーと、可能であれば変更を要求したアプリケーションユーザーを追加します。

現行のRACクラスタと旧来の9i AIXサーバーでは、パフォーマンスの低下は見られませんでした。トランザクションがロールバックされた場合、トリガーがトランザクション内にあるよう

また、それは、監査レコードを挿入しません。

は、人々はあなたがSQLトリガーを使用しないことを言わせてはいけません。トリガで「狂った」ことをしたくないとき(クエリの実行やWebサービスの呼び出しなど)、トリガのための完璧なアプリケーションです(通常は、最後に更新された日付を行に追加するために使用します)正確な情報が得られるようにアプリケーション層を信頼してください)。

+0

ありがとうダグ、それは問題はないが、私はMS SQLサーバーを使用していますが、私は私のポストで私はテーブルのバージョン管理を維持するために一時的なテーブルを使用していると私はトリガーを使用してこれを例外にしたい。 – user3363391

関連する問題