2011-03-25 3 views
13

J'ai créé une fonction sql SQLServer 2008 qui a déclaré une table temporaire et l'utilise pour calculer une moyenne mobile sur les valeurs à l'intérieurUtiliser avec vs déclarer une table temporaire: performance/différence?

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 

mais j'ai aussi trouvé que vous pouvez déclarer le TempTable comme celui-ci :

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: y at-il une grande différence dans ces deux approches? Est-il plus rapide que l'autre ou plus commun/standard? Je pense que la déclaration est plus rapide puisque vous définissez quelles sont 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? l'un puisqu'il doit obtenir toutes les lignes de toute façon, bien que choisir moins de colonnes rend intuitivement que ce serait plus rapide/moins à faire)

J'ai aussi trouvé un create temporary table @table d'ici How to declare Internal table in MySQL? mais je ne veux pas de la table pour persister en dehors de la fonction (je ne suis pas sûr si la table temporaire de création le fait ou non.)

+0

Voici deux exemples de moyennes en cours qui ne nécessitent pas de table temporaire que vous pouvez essayer pour améliorer les performances: https://stackoverflow.com/questions/911326/sql-select-statement-for-calculating -a-running-average-column https: // stackoverflow.com/questions/26618353/t-sql-calculate-moving-average –

Répondre

24

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

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

La plupart du temps, il serait préférable d'utiliser la deuxième option. Vous mentionnez que c'est dans une fonction. S'il s'agit d'un TVF, la plupart du temps, vous voulez que ceux-ci soient en ligne plutôt que multi-instructions afin qu'ils puissent être étendus par l'optimiseur - cela interdirait instantanément l'utilisation de variables de table. Cependant, il peut arriver que la requête sous-jacente soit coûteuse et que vous souhaitiez éviter qu'elle soit exécutée plusieurs fois. Toutefois, vous pouvez déterminer que la matérialisation des résultats intermédiaires améliore les performances dans certains cas spécifiques. Il y a currently no way pour forcer ceci pour les CTEs (without forcing a plan guide at least)

Dans cette éventualité vous (en général) avez 3 options. Un tableau @tablevariable, #localtemp et un tableau ##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 table et les tables #temp see here.

+1

Mentionne aussi les types de tables #temp et ## temp pour la référence – SQLMenace

+0

@SQLMenace - Fait mais je viens juste de remarquer que l'OP l'utilise dans une fonction ainsi gagnée Ne pas être en mesure d'utiliser ces ... –

+0

de sorte que vous ne pouvez pas utiliser le # ou ## à l'intérieur d'une fonction? et oui c'est un TVF, qu'est-ce que tu veux dire par être en ligne? Juste que la syntaxe WITH doit être utilisée? – Mike

9

En plus de ce résultat dans une table temporaire ReadOnly 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 également être écrit comme ceci

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 
+0

Merci pour l'explication de la, Je pensais que ça ferait quelque chose de similaire, mais je n'étais pas sûr – Mike

0

Une autre différence est la deuxième voie (with tableName as ...). Mais dans un premier temps (declare table) vous êtes en mesure de modifier vos données de table.

Questions connexes