【问题标题】:Using with vs declare a temporary table: performance / difference?使用 with vs 声明一个临时表:性能/区别?
【发布时间】:2011-07-23 01:28:55
【问题描述】:

我在 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)
)

问题:这两种方法有很大区别吗?一个比另一个更快或更常见/标准?我认为声明更快,因为您定义了您要查找的列是什么。如果我省略那些列会更快吗?没有用于移动平均线的计算?(不确定这一点,因为无论如何它都必须获取所有行,尽管选择更少的列在直觉上会更快/更少)

我还从这里How to declare Internal table in MySQL? 找到了一个create temporary table @table,但我不希望该表在函数之外持续存在(我不确定创建临时表是否这样做。)

【问题讨论】:

标签: sql performance tsql sql-server-2008


【解决方案1】:

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

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

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

但是,有时(假设底层查询很昂贵,并且您希望避免它被多次执行)您可能会确定在某些特定情况下实现中间结果会提高性能。 currently no way 强制 CTE 执行此操作 (without forcing a plan guide at least)

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

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

【讨论】:

  • 还要提及#temp 和##temp 表类型以供参考
  • @SQLMenace - 完成,但我刚刚注意到 OP 在函数中使用它,因此无法使用这些......
  • 所以你不能在函数中使用#或##?是的,这是一个 TVF,你说他们内联是什么意思?只是应该使用 WITH 语法?
  • @Mike - 是的。您收到错误“无法从函数内访问临时表”。如果你试试。关于第二点stackoverflow.com/questions/2554333/…的一些解释见这个问题
【解决方案2】:

除了马丁的回答

;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

【讨论】:

  • 感谢 with 的解释,我原以为它会做类似的事情,但不确定
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多