2017-10-11 7 views
2

J'utilise la même fonction de fenêtrage dans plusieurs QUAND dans un T-SQL SELECT.Fonction de fenêtre identique dans plusieurs champs dans T-SQL: optimisation?

SELECT 
    ModuleUsage = CASE 
     WHEN Operation = 1 and OperationResult=1 and 1 != LAG(operation) OVER(
      PARTITION BY moduleid, clientname 
      ORDER BY moduleid, clientname, timestamp, operation 
     ) 
      THEN 1 
     WHEN Operation = 2 and OperationResult=3 and 1 = LAG(operation) OVER(
      PARTITION BY moduleid, clientname 
      ORDER BY moduleid, clientname, timestamp, operation 
     ) 
      THEN -1 
     ELSE 0 
    END 
    , * 
FROM [dbo].[LicencesTracing] 

Est-il évalué deux fois ou l'optimiseur de requête réutilise-t-il le résultat une deuxième fois? Merci d'avance

+0

Vous pouvez tester par vous-même. Utilisez 'SET STATISTICS' et faites une requête avec un seul appel de fenêtre. Ensuite, faites votre requête complète avec deux appels. Voyez-vous une différence? –

Répondre

1

Pourrions-nous réécrire la requête comme ci-dessous afin d'avoir la fonction une seule fois?

 -- window function <> 1 
SELECT CASE WHEN LAG(operation) OVER(PARTITION BY moduleid, clientname ORDER BY moduleid, clientname, timestamp, operation) <> 1 

      THEN CASE WHEN Operation = 1 and OperationResult=1 THEN 1 ELSE 0 END 

     -- window function = 1 
     ELSE 

      CASE WHEN Operation = 2 and OperationResult=3 THEN -1 ELSE 0 END 
     END AS ModuleUsage 
     ,* 
FROM [dbo].[LicencesTracing]; 

Et je chose en utilisant IIF va simplifier le code:

SELECT CASE WHEN LAG(operation) OVER(PARTITION BY moduleid, clientname ORDER BY moduleid, clientname, timestamp, operation) <> 1 
      THEN IIF(Operation = 1 and OperationResult=1, 1, 0) 
      ELSE IIF(Operation = 2 and OperationResult=3, -1, 0) 
     END AS ModuleUsage 
     ,* 
FROM [dbo].[LicencesTracing]; 
+0

IIF sera simplement le code s'ils utilisent 2012+;) ... sinon ils vont juste obtenir une erreur –

+0

@AlanBurstein Ils utilisent 2012+ car ils utilisent la fonction 'LAG';) – gotqn

+0

oui ils sont. Duh. Je dois finir mon café avant de commenter davantage. ;) –

1

Vous pouvez déterminer si votre fonction de fenêtre est en cours d'évaluation une fois ou plus en regardant le plan d'exécution réelle (par exemple exécuter le requête avec "Inclure le plan d'exécution réel" activé).

Si vous avez un index en place pour prendre en charge cette fonction de fenêtre, cela n'a pas beaucoup d'importance car l'opération est peu coûteuse. Un POC index serait très utile pour cette requête. L'indice ressemblerait à ceci:

CREATE nonclustered index xxx on dbo.LicencesTracing(moduleid, clientname, timestamp, operation) 
INCLUDE <whatever columns you are returning>; 

Vous pouvez simplifier votre requête et force de l'optimiseur pour évaluer la fonction de fenêtre en calculant dans une sous-requête; quelque chose comme ceci: (notez que je ne peux pas tester ça ...)

SELECT ModuleUsage = CASE 
    WHEN Operation = 1 and OperationResult = 1 and lagOp <> 1 THEN 1 
    WHEN Operation = 2 and OperationResult = 3 and lagOp = 1 THEN -1 ELSE 0 
END 
FROM 
(
    SELECT Operation, OperationResult, lagOp = 
    LAG(operation) OVER(PARTITION BY moduleid, clientname 
        ORDER BY moduleid, clientname, timestamp, operation), * 
    FROM [dbo].[LicencesTracing] 
) sub; 
+0

merci Alan, vous m'avez donné un aperçu très utile de l'optimisation. J'ai marqué la réponse de @ gotqn car il a résolu la question à la racine. –