web-dev-qa-db-fra.com

Utiliser avec vs déclarer une table temporaire: performance/différence?

J'ai créé une fonction SQL dans SQLServer 2008 qui a déclaré une table temporaire et l'utilise pour calculer une moyenne mobile des valeurs contenues dans

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

mais j'ai aussi découvert que vous pouvez déclarer le tempTable comme ceci:

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

Question: Existe-t-il une différence majeure entre ces deux approches? L'un est-il plus rapide que l'autre ou plus commun/standard? Je penserais que la déclaration est plus rapide puisque vous définissez les colonnes que vous recherchez. Serait-il encore plus rapide si je devais omettre les colonnes qui n'étaient pas utilisées dans les calculs de moyenne mobile? celui-ci puisqu'il doit obtenir toutes les lignes de toute façon, bien que sélectionner moins de colonnes ait un sens intuitif, ce serait plus rapide/moins rapide à faire)

J'ai aussi trouvé un create temporary table @table d'ici Comment déclarer une table interne dans MySQL? mais je ne veux pas que la table persiste en dehors de la fonction (je ne suis pas sûr si la création d'une table temporaire le fait ou non.)

14
Mike

La syntaxe @table crée une variable de table (une table réelle dans tempdb) et matérialise les résultats. 

La syntaxe WITH définit un Common Table Expression qui n'est pas matérialisé et est simplement une vue en ligne.

La plupart du temps, il serait préférable d’utiliser la deuxième option. Vous mentionnez que c'est à l'intérieur d'une fonction. S'il s'agit d'un fichier TVF, la plupart du temps, vous souhaitez que ces instructions soient en ligne plutôt qu'en instructions multiples, de sorte qu'elles puissent être développées par l'optimiseur. Cela interdirait immédiatement l'utilisation des variables de table.

Parfois, cependant (vous supposez que la requête sous-jacente est coûteuse et que vous souhaitez éviter son exécution multiple), vous pouvez déterminer que la matérialisation des résultats intermédiaires améliore les performances dans certains cas spécifiques. Il n’existe pour l’instant, aucun moyen de le forcer pour les CTE ( sans forcer au moins un guide de plan )

Dans cette éventualité, vous avez (en général) 3 options. Une table @tablevariable, #localtemp et une table ##globaltemp. Cependant, seul le premier d'entre eux est autorisé pour une utilisation dans une fonction.

Pour plus d’informations sur les différences entre les variables de tableau et les tableaux #temp voir ici .

27
Martin Smith

En plus de ce que Martin a répondu

;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

peut aussi être écrit comme ça

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
10
SQLMenace

La deuxième différence (with tableName as ...) résulte en une table temporaire en lecture seule. Mais dans le premier sens (declare table), vous pouvez modifier les données de votre table.

0
ABS