我的记忆让我失望。我有一个基于触发器的简单审计日志表:
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是更新。
我在审计表中遗漏了什么吗?我的下一步是创建一个仅记录更改的审计表,但您可以提取给定时间范围内的最新记录。对于我的生活,我很难在任何搜索引擎上找到它。链接也会起作用。谢谢你的帮助。
答案 0 :(得分:2)
保持审计历史记录的另一种(更好的?)方法是使用'startDate'和'endDate'列,而不是auditDateTime和AuditCode列。这通常是跟踪数据仓库中类型2更改(行的新版本)的方法。
这使您可以更直接地选择当前行(WHERE 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类更改(您想要跟踪的内容)上有一个很好的部分
上的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