2

私の記憶は私に失敗しています。トリガーに基づく単純な監査ログ テーブル

ID            int (identity, PK)
CustomerID    int               
Name          varchar(255)      
Address       varchar(255)      
AuditDateTime datetime          
AuditCode     char(1)           


があります。次のようなデータが

ID CustomerID Name      Address             AuditDateTime          AuditCode  1  123        Bob       123 Internet Way    2009-07-17 13:18:06.353I          2  123        Bob       123 Internet Way    2009-07-17 13:19:02.117D          3  123        Jerry     123 Internet Way    2009-07-17 13:36:03.517I          4  123        Bob       123 My Edited Way   2009-07-17 13:36:08.050U          5  100        Arnold    100 SkyNet Way      2009-07-17 13:36:18.607I          6  100        Nicky     100 Star Way        2009-07-17 13:36:25.920U          7  110        Blondie   110 Another Way     2009-07-17 13:36:42.313I          8  113        Sally     113 Yet another Way 2009-07-17 13:36:57.627I         


あります。 参考までに、I は挿入、D は削除、U は更新です。

監査テーブルに欠けているものはありますか? 次のステップは、変更のみを記録する監査テーブルを作成することですが、特定の時間枠の最新のレコードを抽出できます。私の人生では、どの検索エンジンでも簡単に見つけることができません。リンクも機能します。助けてくれてありがとう。

4

4 に答える 4

2

わかりました、監査ログ テーブルについていくつか説明します。

ほとんどのアプリケーションでは、監査テーブルの挿入を非常に高速にする必要があります。

監査ログが本当に診断目的であるか、非常に不規則な監査理由である場合、最も迅速な挿入基準は、挿入時にテーブルを物理的に順序付けることです。

これは、監査時間をクラスター化インデックスの最初の列として配置することを意味します。

create unique clustered index idx_mytable on mytable(AuditDateTime, ID)

これにより、AuditDateTime O(log n) および O(1) 挿入時に非常に効率的な選択クエリが可能になります。

CustomerID ごとに監査テーブルを検索する場合は、妥協する必要があります。

(CustomerID, AuditDateTime) に非クラスター化インデックスを追加できます。これにより、顧客ごとの監査履歴の O(log n) ルックアップが可能になりますが、コストは、挿入時の非クラスター化インデックスのメンテナンスになります。 log n) 逆に。

ただし、その挿入時間のペナルティは、CustomerID にインデックスがなく、これが実行される通常のクエリである場合に支払う必要があるテーブル スキャン (つまり、O(n) 時間の複雑さのコスト) よりも望ましい場合があります。不規則なクエリの書き込みプロセスのためにテーブルをロックする O(n) ルックアップはライターをブロックする可能性があるため、リーダーがコミットをブロックしないことが保証されている場合、ライターの利益になる場合があります。それらをサポートするための適切なインデックスがないため、リーダーはテーブルスキャンを行う必要があるため....


追加: 特定の時間枠に制限しようとしている場合、まず最も重要なことは、AuditDateTime のインデックスです。そして、AuditDateTime の順序で挿入するときにクラスター化します。これは、クエリを最初から効率的にするためにできる最大のことです。

次に、特定の期間内のすべての CustomerID の最新の更新を探している場合は、その後も挿入日によって制限されたデータのフル スキャンが必要です。

範囲の間で、監査テーブルに対してサブクエリを実行する必要があります。

select CustomerID, max(AuditDateTime) MaxAuditDateTime 
from AuditTrail 
where AuditDateTime >= @begin and Audit DateTime <= @end

次に、それを適切な選択クエリに組み込みます。

select AuditTrail.* from AuditTrail
inner join 
    (select CustomerID, max(AuditDateTime) MaxAuditDateTime 
     from AuditTrail 
     where AuditDateTime >= @begin and Audit DateTime <= @end
    ) filtration
    on filtration.CustomerID = AuditTrail.CustomerID and 
       filtration.AuditDateTime = AuditTrail.AuditDateTime
于 2009-07-17T23:05:08.883 に答える
2

監査履歴を保持するもう 1 つの (より良い?) 方法は、auditDateTime および AuditCode 列ではなく、'startDate' および 'endDate' 列を使用することです。これは、多くの場合、データ ウェアハウスでタイプ 2 の変更 (行の新しいバージョン) を追跡する際のアプローチです。

これにより、現在の行 (WHERE endDate が NULL) をより直接的に選択できるようになり、更新を挿入または削除とは異なる方法で処理する必要がなくなります。単純に 3 つのケースがあります。

  • 挿入: 開始日と NULL 終了日とともに行全体をコピーします
  • 削除: 既存の現在の行の終了日を設定します (endDate は NULL)。
  • 更新: 削除してから挿入する

あなたの選択は単純です:

select * from AuditTable where endDate is NULL

とにかく、既存のスキーマに対する私のクエリは次のとおりです。

declare @from datetime
declare @to datetime

select b.* from (
  select
    customerId
    max(auditdatetime) 'auditDateTime'
  from
    AuditTable
  where
    auditcode in ('I', 'U')
    and auditdatetime between @from and @to
  group by customerId
  having 
    /* rely on "current" being defined as INSERTS > DELETES */
    sum(case when auditcode = 'I' then 1 else 0 end) > 
    sum(case when auditcode = 'D' then 1 else 0 end)
) a
cross apply(
  select top 1 customerId, name, address, auditdateTime
  from AuditTable
  where auditdatetime = a.auditdatetime and customerId = a.customerId
) b

参考文献

データ ウェアハウスのクリブシートですが、タイプ 2 の変更 (追跡したいもの) に関する適切なセクションがあります。

データ ウェアハウスに関する MSDN ページ

于 2009-07-17T22:58:56.680 に答える
1

別のアプローチは、サブセレクトを使用することです

select a.ID
       , a.CustomerID 
       , a.Name
       , a.Address
       , a.AuditDateTime
       , a.AuditCode
from   myauditlogtable a,
       (select s.id as maxid,max(s.AuditDateTime) 
                 from myauditlogtable as s 
                 group by maxid) 
        as subq
where subq.maxid=a.id;
于 2009-07-17T23:04:08.513 に答える
0

開始時間と終了時間は?たとえば、午前 1 時から午前 3 時の間、
または開始日と終了日の時間のように? 例: 2009-07-17 13:36 から 2009-07-18 13:36 のように

于 2009-07-17T23:05:43.377 に答える