2017-08-23 6 views
0

私はいくつかのテーブル構造を持っているが、以下のようになります:子テーブルが更新されたときに親テーブルの列を更新する最適な方法はありますか?

CREATE TABLE Person 
(
    PersonID INT PRIMARY KEY, 
    Name NVARCHAR(255), 
    LastUpdatedBy INT, 
    LastUpdatedDate DATETIME 
); 

CREATE TABLE Info 
(
    InfoID INT PRIMARY KEY, 
    PersonID INT, 
    Info NVARCHAR(255), 
    LastUpdatedBy INT, 
    LastUpdatedDate DATETIME 
); 

CREATE TABLE Setting 
(
    SettingID INT PRIMARY KEY, 
    PersonID INT, 
    Setting NVARCHAR(255), 
    LastUpdatedBy INT, 
    LastUpdatedDate DATETIME 
); 

私は情報や設定テーブル上のすべての更新がある場合、私は列にPersonテーブルに関連する更新を行う必要がありますということにするために、新しい手順に直面しますLastUpdatedByおよびLastUpdatedDate。

最初に私の頭に浮かぶのは、InfoテーブルまたはSettingテーブルの場合に自動的にPersonテーブルを更新するSQLトリガを作成することです。しかし、いくつかの記事では、SQLトリガを避ける必要があると述べています。

アプリケーションコードを変更することをお勧めする人もいますが、たとえば、

using (var db = new DbContext()) 
{ 
    var result = db.Info.SingleOrDefault(x => x.InfoID == infoID); 
    if (result != null) 
    { 
     result.Info = "Some new value"; 
     result.LastUpdatedBy = userID; 
     result.LastUpdatedDate = DateTime.UtcNow; 
     db.SaveChanges(); 
    } 
} 

のように変更する必要があります。

using (var db = new DbContext()) 
{ 
    var result = db.Info.SingleOrDefault(x => x.InfoID == infoID); 
    if (result != null) 
    { 
     result.Info = "Some new value"; 
     result.LastUpdatedBy = userID; 
     result.LastUpdatedDate = DateTime.UtcNow; 

     var person = db.Person.SingleOrDefault(x => x.PersonID == result.PersonID); 
     if (person != null) 
     { 
      person.LastUpdatedBy = result.LastUpdatedBy; 
      person.LastUpdatedDate = result.LastUpdatedDate; 
     } 
     db.SaveChanges(); 
    } 
} 

実際には、アプリケーションコードが大量であり、多くのコードを変更する必要があります。

30以上のテーブルがあり、それぞれに100,000以上のレコードが含まれているとします。トリガーの作成が可能な場合、それは以下のようになります:

CREATE TRIGGER TriggerName ON dbo.Info 
    AFTER INSERT, UPDATE 
AS 
    BEGIN 
     SET NOCOUNT ON; 
     UPDATE dbo.Person 
     SET  LastUpdatedBy = INSERTED.LastUpdatedBy , 
       LastUpdatedDate = INSERTED.LastUpdatedDate 
     FROM INSERTED 
     WHERE dbo.Person.PersonID = INSERTED.PersonID 
    END 
GO 

は、SQLトリガーは本当にこのシナリオでは避けるべきですか?可能であれば、あなたの答えに基づいて説明してください。どのような代替ソリューションでも、パフォーマンスはまず歓迎です。

+0

トリガーは問題ありませんUPDATEがいくつかの行に影響を与えても、UPDATE文ごとに1回呼び出されますが、これは質問のトリガコードが間違っている理由です - いくつかの行が更新されると失敗します。コードは正常に動作します –

+0

トリガーはベンダー固有のものです** ** - mysql、postgresql、sql-server、oracle、 db2' - または完全に他の何か。 –

+0

@マークは、SET NOCOUNT ONのためSQLサーバを想定し、それに応じてタグ付けされています –

答えて

1

ここでは(パフォーマンスの観点から)トリガーが最適です。これは単に、フロントエンドコードから一連の行に対してupdate文を実行するのと同じです。なぜパフォーマンスペナルティがあると思いますか?あなたのトリガコードは、より多くのこのかかわらず、次のようになります。

CREATE TRIGGER TriggerName ON dbo.Info 
AFTER INSERT, UPDATE 
AS 
BEGIN 
    SET NOCOUNT ON; 
    UPDATE dbo.Person 
    SET  LastUpdatedBy = INSERTED.LastUpdatedBy , 
      LastUpdatedDate = INSERTED.LastUpdatedDate 
    FROM dbo.Person 
      INNER JOIN 
      INSERTED 
      ON dbo.Person.PersonID = INSERTED.PersonID 
END 
GO 

なトランザクション内のすべてのテーブルを更新するストアドプロシージャを作成する、またはあなたのフロントエンドがある場合は(フロントエンドのデータアクセス層を更新するなど、他の方法がありますが、あなたがフロントエンドのコードに更新ステートメントがあった場合、それは悪いデザインなので)専用のクラスがこれらの2つを保持しているので、それは間違って構成されています。

今、私はトリガーが問題から最も簡単な方法だと言いたいのですが、性能のためではありませんが、混乱する結果を招き始めるからです。あなたがデータベースの経験が限られていて、トリガーが何であるのか分からず、「この1つのテーブルだけを更新するたびに、これらの他の27テーブルはすべて魔法によって変わる!どうしたの?私は夢中になっていますか?」 - トリガーは、「すべてのデータをコードを1か所で更新する」というルールを破るため、特定の部分が特定の仕事をしているシステムをエンジニアリングしている人が好きではないのです。

関連する問題