SQL标准从审核日志问题中选择当前记录

时间:2009-07-17 22:41:16

标签: sql logging select audit

我的记忆让我失望。我有一个基于触发器的简单审计日志表:

ID int(identity,PK)
客户id INT
名称 VARCHAR(255)
地址 VARCHAR(255)
AuditDateTime 日期时间
AuditCode 炭(1)


它有这样的数据:

ID 客户id 名称 地址 AuditDateTime AuditCode 1 123 Bob 123 Internet Way 2009-07-17 13:18:06.353 2 123 Bob 123 Internet Way 2009-07-17 13:19:02.117 d 3 123 Jerry 123 Internet Way 2009-07-17 13:36:03.517 4 123 Bob 123我的编辑方式 2009-07-17 13:36:08.050 û 5 100 Arnold 100 SkyNet Way 2009-07-17 13:36:18.607 6 100 Nicky 100 Star Way 2009-07-17 13:36:25.920 û 7 110 Blondie 110另一种方式 2009-07-17 13:36:42.313 8 113 莎莉 113又一种方式 2009-07-17 13:36:57.627


在开始和结束时间之间获取所有最新记录的有效选择语句是什么? FYI:我是插入,D是删除,U是更新。

我在审计表中遗漏了什么吗?我的下一步是创建一个仅记录更改的审计表,但您可以提取给定时间范围内的最新记录。对于我的生活,我很难在任何搜索引擎上找到它。链接也会起作用。谢谢你的帮助。

4 个答案:

答案 0 :(得分:2)

保持审计历史记录的另一种(更好的?)方法是使用'startDate'和'endDate'列,而不是auditDateTime和AuditCode列。这通常是跟踪数据仓库中类型2更改(行的新版本)的方法。

这使您可以更直接地选择当前行(WHERE endDate为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

<强>参考

一个cribsheet for data warehouses,但在第2类更改(您想要跟踪的内容)上有一个很好的部分

data warehousing

上的MSDN页面

答案 1 :(得分:2)

好的,审计日志表有几点。

对于大多数应用程序,我们希望审核表在插入时非常快。

如果审核日志确实用于诊断或非常不正常的审核原因,那么最快的插入标准是在插入时对表进行物理排序。

这意味着将审计时间作为聚集索引的第一列,例如

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

这将允许在AuditDateTime O(log n)和O(1)插入时进行极其高效的选择查询。

如果您希望按客户ID查找审核表,则需要妥协。

您可以在(CustomerID,AuditDateTime)上添加非聚集索引,这将允许O(log n)查找每个客户的审计历史记录,但是成本将是插入时维护该非聚簇索引 - 维护将反之是O(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

答案 2 :(得分: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;

答案 3 :(得分:0)

开始和结束时间?例如在凌晨1点到凌晨3点之间  或者开始和结束日期时间?例如在2009-07-17 13:36到2009-07-18 13:36