2011-07-12 4 views
2

J'ai une fonction scalaire à valeur appelée DATEONLY qui retourne DATEADD (DD, 0, DATEDIFF (DD, 0, @DATETIME)), comme ceci:SQL Server me montre différentes rowcounts en utilisant les fonctions Valued Scalar-

CREATE FUNCTION [DBO].[DATEONLY] (@DATETIME DATETIME) 
RETURNS DATETIME 
BEGIN 
    RETURN DATEADD(DD, 0, DATEDIFF(DD, 0, @DATETIME)) 
END 

Lorsque je sélectionne une table à l'aide de ma fonction, le SQL Server Profiler compte un nombre élevé de RowCounts que si j'ai utilisé directement DATEADD (DD, 0, DATEDIFF (DD, 0, @DATETIME)).

Dans mon dossier public Dropbox, vous pouvez trouver un script.sql qui peut reproduire ce dont je parle et vous pouvez également trouver un Trace.trc à partir de mon profileur SQL Server.

script.sql: https://www.dropbox.com/s/gwbh54jqas7fhhc/script.sql

trace.trc: https://www.dropbox.com/s/gwbh54jqas7fhhc/Trace.trc

Juste pour simplifier, regardez les rowcounts ci-dessous.

SELECT DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) AS DATA, COUNT(*) AS SOULS 
FROM HELL 
GROUP BY DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) 

rowcounts = 6

SELECT DBO.DATEONLY(INCOMING) AS DATA, COUNT(*) AS SOULS 
FROM HELL 
GROUP BY DBO.DATEONLY(INCOMING) 

rowcounts = 32

Dans mon scénario réel, ces 32 lignes se transforme en rowcounts de millions. S'ils sont LA MÊME CHOSE, que se passe-t-il ?! Comment puis-je optimiser cela pour éviter de changer toute l'application?

Merci beaucoup!

Répondre

3

L'exécution de fonction définie par l'utilisateur à l'échelle scalaire n'est pas très efficace dans le serveur sql - elle exécute essentiellement un appel d'exécution distinct pour chaque appel, qui correspond à chaque ligne de la table. Adam Machanic a un bon post sur ce sujet qui décrit l'exécution de UDF scalaire et comment l'exécution de la fonction table en ligne peut être beaucoup plus rapide.

Vous pouvez réécrire votre requête pour profiter de la logique dans un fichier tvf, que l'optimiseur exécute en utilisant le même plan de requête que votre requête étendue originale et affiche le même RowCounts = 5 pendant l'exécution.

CREATE FUNCTION [DBO].[DATEONLY2] (@DATETIME DATETIME) RETURNS TABLE 
AS RETURN SELECT DATEADD(DD, 0, DATEDIFF(DD, 0, @DATETIME)) data 

select data, count(*) as souls 
from 
(SELECT (select data from dbo.dateonly2(incoming)) data 
FROM HELL) t 
GROUP BY data 
0

Je suggère d'utiliser la requête suivante

SELECT DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) AS DATA, COUNT(*) AS SOULS 
FROM HELL 
GROUP BY DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) 

vous pouvez créer un index sur la colonne d'entrée pour éviter la degration performance.

Questions connexes