使用with vs声明一个临时表:性能/差异?

时间:2011-03-25 16:33:07

标签: sql performance tsql sql-server-2008

我在 SQLServer 2008 中创建了一个sql函数,该函数声明了一个临时表并使用它来计算内部值的移动平均值

declare @tempTable table 
    (
        GeogType nvarchar(5),
        GeogValue nvarchar(7),
        dtAdmission date,
        timeInterval int,
        fromTime nvarchar(5),
        toTime nvarchar(5),
        EDSyndromeID tinyint,
        nVisits int
    )
insert @tempTable select * from aces.dbo.fEDVisitCounts(@geogType, @hospID,DATEADD(DD,-@windowDays + 1,@fromDate),
                @toDate,@minAge,@maxAge,@gender,@nIntervalsPerDay, @nSyndromeID)


    INSERT @table (dtAdmission,EDSyndromeID, MovingAvg) 
    SELECT list.dtadmission
        , @nSyndromeID
        , AVG(data.nVisits) as MovingAvg
    from @tempTable as list 
        inner join @tempTable as data  
    ON list.dtAdmission between data.dtAdmission and DATEADD(DD,@windowDays - 1,data.dtAdmission) 
    where list.dtAdmission >= @fromDate
    GROUP BY list.dtAdmission

但我也发现你可以像这样声明tempTable:

with tempTable as 
(
    select * from aces.dbo.fEDVisitCounts('ALL', null,DATEADD(DD,-7,'01-09-2010'),
        '04-09-2010',0,130,null,1, 0)
)

问题:这两种方法有很大差异吗?是一个比另一个更快还是更常见/标准?我认为声明更快,因为你定义了你正在寻找的列是什么..如果我省略列那么它也会更快没有用于移动平均线的计算?(不确定这个,因为它必须得到所有的行,但是选择较少的列直观地感觉它会更快/更少)

我也从这里找到create temporary table @table How to declare Internal table in MySQL?但是我不希望表在函数外部持久存在(我不确定创建临时表是否执行此操作。)

3 个答案:

答案 0 :(得分:27)

@table语法创建一个表变量(tempdb中的实际表)并将结果具体化。

WITH语法定义了一个Common Table Expression,它没有具体化,只是一个内联视图。

大多数情况下,您最好使用第二个选项。你提到这是一个功能。如果这是一个TVF,那么大多数时候你希望这些是内联而不是多语句,这样它们就可以被优化器扩展 - 这会立即禁止使用表变量。

然而,有时候(假设基础查询很昂贵并且您希望避免多次执行),您可能会确定实现中间结果会在某些特定情况下提高性能。对于CTE(currently no way

without forcing a plan guide at least强制执行此操作

在这种情况下,您(一般情况下)有3个选项。 @tablevariable#localtemp表和##globaltemp表。但是,只有第一个允许在函数内使用。

有关表变量和#temp表see here之间差异的更多信息。

答案 1 :(得分:10)

除了马丁的回答

;with tempTable as 
(
    select * from aces.dbo.fEDVisitCounts('ALL', null,DATEADD(DD,-7,'01-09-2010'),
        '04-09-2010',0,130,null,1, 0)
)

SELECT * FROM tempTable

也可以像这样写

SELECT * FROM 
(
    select * from aces.dbo.fEDVisitCounts('ALL', null,DATEADD(DD,-7,'01-09-2010'),
        '04-09-2010',0,130,null,1, 0)
) AS tempTable  --now you can join here with other tables

答案 2 :(得分:0)

另一个区别是第二种方式(with tableName as ...)导致ReadOnly临时表。但是以第一种方式(declare table),您可以更改表格数据。