4

多くのデータを返すか、変更を照会するのが難しいアプリを介して更新されるテーブルが多数あります。この問題を回避するために、単一行の「LastUpdated」テーブルを作成し、LastUpdated テーブルの適切な列に対して GetDate() を設定するだけのこれらの複雑なテーブルにトリガーを設定しました。

CREATE TRIGGER [dbo].[trg_ListItem_LastUpdated] ON [dbo].[tblListItem] 
FOR INSERT, UPDATE, DELETE 
AS
UPDATE LastUpdated SET ListItems = GetDate()
GO

このように、クライアントはこのテーブルに最後に更新された値を照会するだけでよく、複雑なテーブルからデータを更新する必要があるかどうかを判断できます。複雑なテーブルは、スナップショット分離を使用してダーティ リードを防止しています。

忙しいシステムでは、「LastUpdated」での更新の競合が原因で、1 日に 1 回程度、複雑なテーブルのデータの書き込みまたは更新でエラーが発生します。これはトリガーによって実行されるステートメントで発生するため、影響を受ける複合テーブルはデータの保存に失敗します。次のエラーが記録されます。

更新の競合により、スナップショット分離トランザクションが中止されました。スナップショット分離を使用して、データベース 'devDB' のテーブル 'dbo.tblLastUpdated' に直接的または間接的にアクセスし、別のトランザクションによって変更または削除された行を更新、削除、または挿入することはできません。トランザクションを再試行するか、更新/削除ステートメントの分離レベルを変更してください。

この失敗を防ぐために、トリガーでここで何をすべきですか? これを回避するために、トリガーである種のクエリヒントを使用できますか?または、トリガーのエラーを無視できますか? LastUpdated のデータを更新することは重要ではありませんが、複雑なテーブルにデータを正しく保存することは重要です。

これはおそらく、私が見落としている、または気づいていない非常に単純なことです。いつものように、情報をありがとう。

4

4 に答える 4

3

Change Tracking( http://msdn.microsoft.com/en-gb/library/cc280462%28v=sql.100%29.aspx )を使用することを検討する必要があると思います。これは、使用できる軽量の組み込み SQL Server 機能です。個々の変更をログに記録するのではなく、テーブルが変更されたという事実を監視します (これは で行うこともできますChange Data Capture)。すでに使用しているスナップショット分離が必要です。

トリガーが親トランザクションで実行されており、スナップショットが古くなっているため、トランザクション全体をもう一度開始する必要があります。これが複雑なワークロードである場合、最後に更新されたデータをこのように維持するにはコストがかかります。

于 2013-04-24T13:14:50.870 に答える
1

短い答え - しないでください! 更新されたトランザクションを単一の共有行に依存させると、デッドロックが発生しやすくなり、更新の競合が厄介なものの全範囲になります。

次のように、ビューを使用して最後の更新を確認できます。

SELECT
    t.name
    ,user_seeks
    ,user_scans
    ,user_lookups
    ,user_updates
    ,last_user_seek
    ,last_user_scan
    ,last_user_lookup
    ,last_user_update
FROM sys.dm_db_index_usage_stats i JOIN sys.tables t 
    ON (t.object_id = i.object_id)
WHERE database_id = db_id()

または、 LastUpdateを使用したソリューションを本当に主張する場合は、自律的なトランザクションのトリガーからの更新を実装できます。SQL Server は自律型トランザクションをサポートしていませんが、好きなサーバーを使用して行うことができます: SQL Server 2008 で自律型トランザクションを作成する方法

于 2013-04-24T05:22:16.897 に答える
0

または、アプリケーション内の複雑なテーブルを更新するために使用するのと同じトランザクション内でログ テーブルを更新し、トリガーを完全に回避することもできます。

更新テーブル 内の同じ行を更新する代わりに、新しい行を挿入することもできLastUpdatedます。次に、最新の更新の最大タイムスタンプを照会できます。ただし、このアプローチでは、LastUpdatedテーブルが毎日大きくなり、トランザクションの量が多い場合に注意する必要があります。

于 2013-04-24T05:53:49.317 に答える