web-dev-qa-db-ja.com

vsを使用して一時テーブルを宣言:パフォーマンス/違い?

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

質問:これら2つのアプローチに大きな違いはありますか? 1つは他のよりも一般的/標準よりも速いですか?探している列が何であるかを定義しているので、宣言の方が速いと思います。移動平均の計算で使用されなかった列を省略するには?

ここからcreate temporary table @tableも見つかりました MySQLで内部テーブルを宣言する方法は? ですが、関数の外でテーブルを永続化したくありません(一時的な作成かどうかはわかりません)テーブルはこれを行うかどうかを指定します。)

17
Mike

@table構文は、テーブル変数(tempdb内の実際のテーブル)を作成し、その変数に結果を具体化します。

WITH構文は Common Table Expression を定義します。これは具体化されておらず、単なるインラインビューです。

ほとんどの場合、2番目のオプションを使用したほうがよいでしょう。あなたはこれが関数の中にあると述べました。これがTVFの場合、ほとんどの場合、これらをマルチステートメントではなくインラインにして、オプティマイザーで展開できるようにします。これにより、テーブル変数の使用が即座に禁止されます。

ただし、場合によっては(基になるクエリが高価で、複数回実行されないようにする場合など)、中間結果を具体化することで特定のケースでパフォーマンスが向上すると判断する場合があります。 現在、CTEにこれを強制する方法はありません少なくとも計画ガイドを強制せずに

その結果、あなたは(一般的に)3つのオプションを持っています。 A @tablevariable#localtempテーブルと##globaltemp テーブル。ただし、関数内での使用が許可されているのは最初の1つだけです。

テーブル変数と#tempテーブル の違いに関する詳細については、こちら を参照してください。

28
Martin Smith

マーティンの答えに加えて

;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
11
SQLMenace

もう1つの違いは2番目の方法です(with tableName as ...)は読み取り専用の一時テーブルになります。しかし、最初の方法(declare table)テーブルデータを変更できます。

0
ABS