我有一张桌子(让我们称之为日志),有几百万条记录。我有Id,Count,FirstHit,LastHit。
此表只有任何给定Id的记录
每天我都会进入另一张桌子(让我们称之为“饲料”),其中包含大约五十万条记录,其中包括这些字段:
此表可以包含许多相同ID的记录
我想要做的是以下列方式更新日志。 计数 - 日志计数值,加上在Feed中找到的该ID的记录的count() FirstHit - 日志中最早的当前值或该id的feed中的最小值 LastHit - 日志中当前值的最新值或该ID的Feed中的最大值。
应该注意的是,Feed中的许多ID都已记录在日志中。
有用的简单方法是创建一个临时表,并在其中插入两者的并集,如
Select Id, Min(Timestamp) As FirstHit, MAX(Timestamp) as LastHit, Count(*) as Count FROM feed GROUP BY Id
UNION ALL
Select Id, FirstHit,LastHit,Count FROM log;
从那个临时表中我做了一个聚合Min(第一个),最大(最后一个)和总和(计数)的选择
Select Id, Min(FirstHit),Max(LastHit),Sum(Count) FROM @temp GROUP BY Id;
这给了我最终的结果。然后,我可以从日志中删除所有内容,并将其替换为带有temp的所有内容,或者为常见记录创建更新并插入新记录。但是,我认为两者效率都很低。
有没有更有效的方法来做到这一点。也许在日志表中进行更新?
答案 0 :(得分:2)
如果您的SQL Server版本是2008或更高版本,那么您可以尝试:
MERGE INTO log l
USING (SELECT Id, MIN(Timestamp) AS FirstHit, MAX(Timestamp) AS LastHit, Count(*) as Count FROM feed GROUP BY Id) f
ON l.Id = f.Id
WHEN MATCHED THEN
UPDATE SET
FirstHit = CASE WHEN l.FirstHit < f.FirstHit THEN l.FirstHit ELSE f.FirstHit END,
LastHit = CASE WHEN l.LastHit > f.LastHit THEN l.LastHit ELSE f.LastHit END,
Count = l.Count + f.Count
WHEN NOT MATCHED THEN
INSERT (Id, FirstHit, LastHit, Count)
VALUES (f.Id, f.FirstHit, f.LastHit, f.Count);
答案 1 :(得分:1)
此处的关键字为EVERYDAY
。您应该有一个(批处理)作业,在每天结束时运行该过程。这个想法只处理来自昨天的记录,这比处理整个Feed
表更好。
Feed表仅包含上次运行日期的匹配。使用MERGE更新Log
表格更容易:
注意:我们可以说FirstHit
永远不会更新。仅限LastHit
和Count
。从@dened回答改进。
MERGE INTO log l
USING (SELECT Id, MIN(Timestamp) AS FirstHit, MAX(Timestamp) AS LastHit, Count(*) as TodayHit FROM feed GROUP BY Id) f
ON l.Id = f.Id
WHEN MATCHED THEN
UPDATE SET
LastHit = f.LastHit,
Count = l.Count + f.TodayHit
WHEN NOT MATCHED THEN
INSERT (Id, FirstHit, LastHit, Count)
VALUES (f.Id, f.FirstHit, f.LastHit, f.TodayHit);
答案 2 :(得分:0)
我无法测试它,但我认为这应该可行,但不确定它的表现如何:
select
ifnull(log.Id,feedsum.Id) as Id
, case when log.FirstHit is null then feedsum.FirstHit
when feedsum.FirstHit is null then log.FirstHit
when log.FirstHit<feedsum.FirstHit then log.FirstHit
else feedsum.FirstHit as FirstHit
, case when log.LastHit is null then feedsum.LastHit
when feedsum.LastHit is null then log.LastHit
when log.LastHit>feedsum.LastHit then log.LastHit
else feedsum.LastHit as LastHit
from
log
full outer join (
Select Id, Min(Timestamp) As FirstHit, MAX(Timestamp) as LastHit, Count(*) as Count FROM feed GROUP BY Id
) feedsum using (Id)