在SQL中避免嵌套子查询

时间:2009-05-13 03:44:57

标签: sql sql-server join

我有一个SQL表,其中包含以下格式的数据:

Id int EventTime dateTime CurrentValue int

对于给定的id,该表可能有多行,表示随时间变化的值(EventTime标识值更改的时间)。

鉴于某个特定时间点,我希望能够计算每个给定值的不同ID的数量。

现在,我正在使用嵌套子查询和临时表,但它看起来效率会更高。

SELECT [Id],   
(  
    SELECT  
        TOP 1 [CurrentValue]  
    FROM [ValueHistory]  
    WHERE [Ids].[Id]=[ValueHistory].[Id] AND
        [EventTime] < @StartTime  
    ORDER BY [EventTime] DESC  
) as [LastValue]  
INTO #temp  
FROM [Ids]  

SELECT [LastValue], COUNT([LastValue])
FROM #temp  
GROUP BY [LastValue]  
DROP TABLE #temp

3 个答案:

答案 0 :(得分:1)

这是我的第一次去:

select ids.Id, count( distinct currentvalue)
from ids
join valuehistory vh on ids.id = vh.id
where vh.eventtime < @StartTime
group by ids.id

但是,我不确定我非常清楚你的桌面模型,或者你想要解决的具体问题。

这将是:在每个Id的特定日期之前,来自valuehistory的不同“当前值”。

这就是你要找的东西吗?

答案 1 :(得分:1)

我想我理解你的问题。

您希望获取每个ID的最新值,按该值获取组,然后查看有多少ID具有相同的值?这是对的吗?

如果是这样,这是我的第一次拍摄:

declare @StartTime datetime
set @StartTime = '20090513'

select ValueHistory.CurrentValue, count(ValueHistory.id)
from
(
    select id, max(EventTime) as LatestUpdateTime
    from ValueHistory
    where EventTime < @StartTime
    group by id
) CurrentValues
inner join ValueHistory on CurrentValues.id = ValueHistory.id
and CurrentValues.LatestUpdateTime = ValueHistory.EventTime
group by ValueHistory.CurrentValue

不能保证这实际上更快 - 为了能够以任何合适的速度工作,你需要一个关于EventTime的索引。

答案 2 :(得分:0)

让我们记住,因为SQL语言描述了你想要的而不是如何获得它,所以有很多方法可以表达一个查询,最终将由一个好的查询优化器转换成相同的查询执行计划。当然,“好”的级别取决于您正在使用的数据库。

通常,子查询只是一种语法上不同的描述连接的方式。查询优化器将识别这一点,并尽其所能确定执行查询的最佳方法。可以根据需要创建临时表。因此,在许多情况下,重新处理查询将对您的实际执行时间无效 - 它最终可能会出现在同一个查询执行计划中。

如果您要尝试优化,则需要通过对该查询进行描述来检查查询计划。确保它不对大​​表进行全表扫描,并尽可能选择适当的索引。如果且仅当它在此处进行次优选择时,您是否应该尝试手动优化查询。

现在,尽管如此,您粘贴的查询并不完全符合您所说的“计算每个给定值的不同ID的计数”的目标。如果我不能满足您的需求,请原谅我,但这里有针对您当前查询的性能测试。 (语法是近似的,对不起 - 远离我的桌子)。

SELECT [IDs].[Id], vh1.[CurrentValue], COUNT(vh2.[CurrentValue]) FROM
    [IDs].[Id] as ids JOIN [ValueHistory] AS vh1 ON ids.[Id]=vh1.[Id]
        JOIN [ValueHistory] AS vh2 ON vh1.[CurrentValue]=vh2.[CurrentValue]
GROUP BY [Id], [LastValue];

请注意,通过添加索引以使这些连接优于重新执行查询,您可能会看到更好的性能提升,假设您愿意将性能命中更新为更新操作。