Grande différence de performance (1 heure à 1 minute) trouvée dans SQL. Pouvez-vous expliquer pourquoi?

StackOverflow https://stackoverflow.com/questions/1819513

Question

Les requêtes suivantes prennent respectivement 70 minutes et 1 minute sur une machine standard pour 1 million d’enregistrements. Quelles pourraient être les raisons possibles?

Requête [01:10:00]

SELECT * 
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
    CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')        
        THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')        
        ELSE sys.fn_cdc_increment_lsn(0x00) END
    , sys.fn_cdc_get_max_lsn()
    , 'all with mask') 
WHERE __$operation <> 1

Requête modifiée [00:01:10]

DECLARE @MinLSN binary(10)
DECLARE @MaxLSN binary(10)
SELECT @MaxLSN= sys.fn_cdc_get_max_lsn()
SELECT @MinLSN=CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')     
        THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')        
        ELSE sys.fn_cdc_increment_lsn(0x00) END

SELECT * 
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
        @MinLSN, @MaxLSN, 'all with mask') WHERE __$operation <> 1

[Modifié]

J'ai essayé de recréer le scénario avec une fonction similaire pour voir si les paramètres sont évalués pour chaque ligne.

CREATE FUNCTION Fn_Test(@a decimal)RETURNS TABLE
AS
RETURN
(
    SELECT @a Parameter, Getdate() Dt, PartitionTest.*
    FROM PartitionTest
);

SELECT * FROM Fn_Test(RAND(DATEPART(s,GETDATE())))

Mais je reçois la même valeur pour la colonne "Paramètre" pour un million d'enregistrements traités en 38 secondes.

Était-ce utile?

La solution

Même les fonctions scalaires déterministes sont évaluées au moins une fois par ligne. Si la même fonction scalaire déterministe apparaît plusieurs fois sur la même " ligne " avec les mêmes paramètres, je crois que ce n’est qu’alors qu’il sera évalué une fois - p. ex. dans un CASE WHEN fn_X (a, b, c) > 0 ALORS fn_X (a, b, c) SAUF 0 FIN ou quelque chose comme ça.

Je pense que votre problème RAND est dû au fait que vous continuez à réensemencer:

  

Appels répétitifs de RAND () avec le   la même valeur de départ retourne la même chose   résultats.

     

Pour une connexion, si RAND () est   appelé avec une valeur de départ spécifiée,   tous les appels suivants de RAND () produisent   résultats basés sur la graine RAND ()   appel. Par exemple, la requête suivante   retournera toujours la même séquence   des nombres.

J'ai commencé à mettre en cache les résultats des fonctions scalaires, comme vous l'avez indiqué, allant même jusqu'à précalculer les tables des résultats des fonctions scalaires et à les joindre. Il faut éventuellement faire quelque chose pour que les fonctions scalaires fonctionnent. Bien sûr que non, la meilleure option est le CLR - apparemment, ils surpassent de loin les UDF SQL. Malheureusement, je ne peux pas les utiliser dans mon environnement actuel.

Autres conseils

Dans votre première requête, vos fn_cdc_increment_lsn et fn_cdc_get_min_lsn sont exécutés pour chaque ligne. Deuxième exemple, une seule fois.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top