2016-06-21 5 views
0

MS-SQL Server 2014データベースで、データベースのトリガのパフォーマンスに問題があります。それは基本的に何AFTER UPDATEトリガでUPDATEのパフォーマンスに関する問題が発生する

CREATE TRIGGER [dbo].[TRG_T_TPM_Vehicle_Update] ON [dbo].[T_TPM_Vehicle] 
    AFTER UPDATE 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 
UPDATE T_TPM_Vehicle SET LastUpdated = getdate() 
     WHERE Vehicle_Number IN (SELECT Vehicle_Number FROM inserted) 

UPDATE T_TPM_Vehicle SET [DisturbedSince] = getdate() 
     WHERE Vehicle_Number IN (SELECT Vehicle_Number FROM inserted WHERE inserted.Emergency_Stop = 1) 
     AND Vehicle_Number IN (SELECT Vehicle_Number FROM deleted WHERE deleted.Emergency_Stop = 0) 

INSERT INTO T_TPM_Vehicle_HistoricalData 
     ([Vehicle_Ref] 
     ,[Vehicle_Number] 
     ,[Vehicle_Type] 
     ,[Pos_X] 
     ,[Pos_Y] 
     ,[Alpha] 
     ,[LastAutoPos_X] 
     ,[LastAutoPos_Y] 
     ,[LastAutoAlpha] 
     ,[Automatic] 
     ,[Manual] 
     ,[Blocked] 
     ,[Loaded] 
     ,[Stoped] 
     ,[Emergency_Stop] 
     ,[User_Required] 
     ,[BatteryAlmostEmpty] 
     ,[BatteryEmpty] 
     ,[BatteryLevel] 
     ,[ChargingRelaisEnable] 
     ,[NavOK] 
     ,[PowerOn] 
     ,[Available] 
     ,[OperatingMinutes] 
     ,[UpdateOperatingMinutes] 
     ,[DataChangedByVIS] 
     ,[Blockingsreleased] 
     ,[Cancelled] 
     ,[ProductID] 
     ,[HUIdent1] 
     ,[HUIdent2] 
     ,[HUType] 
     ,[DisturbedSince]) 
SELECT inserted.[Vehicle_Ref] 
    ,inserted.[Vehicle_Number] 
    ,inserted.[Vehicle_Type] 
    ,inserted.[Pos_X] 
    ,inserted.[Pos_Y] 
    ,inserted.[Alpha] 
    ,inserted.[LastAutoPos_X] 
    ,inserted.[LastAutoPos_Y] 
    ,inserted.[LastAutoAlpha] 
    ,inserted.[Automatic] 
    ,inserted.[Manual] 
    ,inserted.[Blocked] 
    ,inserted.[Loaded] 
    ,inserted.[Stoped] 
    ,inserted.[Emergency_Stop] 
    ,inserted.[User_Required] 
    ,inserted.[BatteryAlmostEmpty] 
    ,inserted.[BatteryEmpty] 
    ,inserted.[BatteryLevel] 
    ,inserted.[ChargingRelaisEnable] 
    ,inserted.[NavOK] 
    ,inserted.[PowerOn] 
    ,inserted.[Available] 
    ,inserted.[OperatingMinutes] 
    ,inserted.[UpdateOperatingMinutes] 
    ,inserted.[DataChangedByVIS] 
    ,inserted.[Blockingsreleased] 
    ,inserted.[Cancelled] 
    ,inserted.[ProductID] 
    ,inserted.[HUIdent1] 
    ,inserted.[HUIdent2] 
    ,inserted.[HUType] 
    ,inserted.[DisturbedSince] 
FROM inserted 
END 

は、それが挿入された内のすべての行と挿入された行のサブセットについてDisturbedSince列のLastUpdated列を設定しています。

最後に、挿入された行が履歴テーブルにコピーされます。 (行の変更はすべて2日間保存する必要があります)。古いデータはメンテナンスジョブによって削除されます。

1秒あたり〜300個の行が更新されます(行の更新はまとめてバッチ処理できます)。大量のデータと再帰的な更新を作成します。

私はトリガによって引き起こされた再帰的なUPDATE問題を解決するようなINSTEAD OF UPDATEトリガを見つけましたが、挿入されたテーブルのすべての行を1つずつトリガのupdate文で処理する必要があります。

これが本当に高速かどうかはわかりません。あなたの誰かがお勧めですか?

本当に必要なのは、テーブルに送信する前にデータ行を調整/拡張することです。これにはアプローチがありますか?

例えば:のような何か:履歴テーブルに変更されたデータの格納と

UPDATE TRIGGER AFTER
CREATE TRIGGER ... INSTEAD OF UPDATE 
AS 
BEGIN 
    UPDATE inserted SET LastUpdated = getdate() 
    UPDATE inserted SET DisturbedSince 
    WHERE Vehicle_Number IN (SELECT Vehicle_Number FROM inserted WHERE inserted.Emergency_Stop = 1) 
     AND Vehicle_Number IN (SELECT Vehicle_Number FROM deleted WHERE deleted.Emergency_Stop = 0) 
    "SAVE INSERTED" 
END 

と。

ありがとうございます。

トーマス

+1

これはどのRDBMSですか?トリガは**ベンダー固有のもの** ** mysql、 'postgresql'、' sql-server'、 'oracle'、' db2'などを使用するかどうかを指定するタグを追加してください。 –

+0

"私は挿入されたテーブルのすべての行を1つずつトリガ内の更新ステートメントで処理しなければならないでしょう。" - ええ、なぜあなたはそれを信じますか? –

+0

@Marc:MS-SQL Server 2014データベースです。これを私の質問に加えました。 –

答えて

1

あなたにも同じテーブル内のデータを変更したいしているときは、INSTEAD OFトリガーを使用すると、AFTERトリガーではなく行くための正しい方法であると考えるのが正しいです。

それはのようになります。

CREATE TRIGGER [dbo].[TRG_T_TPM_Vehicle_Update] ON [dbo].[T_TPM_Vehicle] 
    INSTEAD OF UPDATE 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

UPDATE tgt 
SET 
    Vehicle_Ref = i.Vehicle_Ref, 
    Vehicle_Type = i.Vehicle_Type, 
    ... 
    LastUpdated = getdate(), 
    DisturbedSince = CASE WHEN i.Emergency_Stop=1 and d.Emergency_Stop=0 
        THEN getdate() ELSE d.DisturbedSince END 
OUTPUT 
    inserted.[Vehicle_Ref] 
    ,inserted.[Vehicle_Number] 
    ,inserted.[Vehicle_Type] 
    ... 
    ,inserted.[HUIdent2] 
    ,inserted.[HUType] 
    ,inserted.[DisturbedSince] 
INTO T_TPM_Vehicle_HistoricalData 
     ([Vehicle_Ref] 
     ,[Vehicle_Number] 
     ,[Vehicle_Type] 
     ... 
     ,[HUIdent2] 
     ,[HUType] 
     ,[DisturbedSince]) 
FROM 
    T_TPM_Vehcile tgt 
     inner join 
    inserted i 
     on 
     tgt.Vehicle_Number = i.Vehicle_Number 
     inner join 
    deleted d 
     on 
     tgt.Vehicle_Number = d.Vehicle_Number 

あなたは、私は、単一の複合文にUPDATE sおよび履歴テーブルにINSERTの両方を組み合わせたことに注意しましょう。

あなたはまた、2つのinserted sがここに遊びに存在するため、それは少し混乱だことに注意しましょう - (混乱のいくつかを回避するためにiとしてエイリアス)トリガーの一部としてinsertedinsertedOUTPUT句の一部として、 。

+0

ありがとうございます。私は試してみます –

+0

DisturbedSinceの "更新"では、それはケースであるはずですね...それ以降... ELSE d.DisturbedSince END? –

+0

@ThomasVoß - はい、申し訳ありません。私はコードをテストすることはできませんので、あなたのテーブルを持っていない。 –

関連する問題