Использование с vs объявляет временную таблицу: производительность/разность?

Я создал sql-функцию в SQLServer 2008, которая объявила временную таблицу и использует ее для вычисления скользящей средней по значениям внутри

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,[email protected] + 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 отсюда Как объявить внутреннюю таблицу в MySQL?, но я не хочу, чтобы таблица сохранялась за пределами функции ( Я не уверен, делает ли это временную таблицу create или нет.)

Ответы

Ответ 1

Синтаксис @table создает переменную таблицы (фактическую таблицу в tempdb) и материализует результаты.

Синтаксис WITH определяет Common Table Expression, который не является материализованным и является только встроенным представлением.

В большинстве случаев вам будет лучше использовать второй вариант. Вы говорите, что это внутри функции. Если это TVF, то большую часть времени вы хотите, чтобы они были встроенными, а не многозадачными, поэтому они могут быть расширены оптимизатором - это немедленно запретит использование табличных переменных.

Иногда (например, основной запрос стоит дорого, и вы хотите избежать его выполнения несколько раз), вы можете определить, что материализация промежуточных результатов повышает производительность в некоторых конкретных случаях. Существует в настоящее время нет пути для этого для CTE (без принуждения план по крайней мере)

В этом случае у вас (в общем) есть 3 варианта. A @tablevariable, #localtemp и таблицы ##globaltemp. Однако только первая из них разрешена для использования внутри функции.

Для получения дополнительной информации о различиях между табличными переменными и таблицами #temp см. здесь.

Ответ 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

Ответ 3

Другим отличием является второй способ (with tableName as ...) привести к временной таблице ReadOnly. Но в первую очередь (declare table) вы можете изменить свои данные таблицы.