8

J'ai écrit un fichier UDF à valeur table qui commence par un CTE pour renvoyer un sous-ensemble des lignes d'une grande table. Il existe plusieurs jointures dans le CTE. Un couple d'internes et un à gauche se joignent à d'autres tables, qui ne contiennent pas beaucoup de lignes. Le CTE comporte une clause where qui renvoie les lignes dans une plage de dates, afin de renvoyer uniquement les lignes nécessaires.CTE SQL Server référencé dans les jointures lentes

Je référence alors ce CTE dans 4 jointures à gauche, afin de construire des sous-totaux en utilisant différents critères.

La requête est assez complexe, mais voici une pseudo-version simplifiée de celui-ci

WITH DataCTE as 
(
    SELECT [columns] FROM table 
         INNER JOIN table2 
         ON [...] 

         INNER JOIN table3 
         ON [...] 

         LEFT JOIN table3 
         ON [...] 
) 
SELECT [aggregates_columns of each subset] FROM DataCTE Main 
LEFT JOIN DataCTE BananasSubset 
       ON [...] 
      AND Product = 'Bananas' 
      AND Quality = 100 
LEFT JOIN DataCTE DamagedBananasSubset 
       ON [...] 
      AND Product = 'Bananas' 
      AND Quality < 20 
LEFT JOIN DataCTE MangosSubset 
       ON [...] 
GROUP BY [ 

J'ai le sentiment que SQL Server devient confus et appelle le CTE pour chaque jointure réflexive, ce qui semble confirmé en regardant le plan d'exécution, bien que j'avoue ne pas être un expert en les lisant.

J'aurais supposé que SQL Server était suffisamment intelligent pour effectuer une seule fois la récupération de données à partir du CTE, plutôt que de le faire plusieurs fois. J'ai essayé la même approche mais plutôt que d'utiliser un CTE pour obtenir le sous-ensemble des données, j'ai utilisé la même requête de sélection que dans le CTE, mais je l'ai fait sortir dans une table temporaire à la place.

La version référençant la version CTE prend 40 secondes. La version référençant la table temporaire prend entre 1 et 2 secondes.

Pourquoi SQL Server n'est-il pas assez intelligent pour conserver les résultats du CTE en mémoire? J'aime les CTE, particulièrement dans ce cas, car mon UDF est une table, donc cela m'a permis de tout garder dans une seule déclaration.

Pour utiliser une table temporaire, j'aurais besoin d'écrire une table UDF à plusieurs tables, ce que je trouve une solution légèrement moins élégante. Est-ce que certains d'entre vous ont eu ce genre de problèmes de performance avec CTE, et si oui, comment les avez-vous triés?

Merci,

Kharlos

+0

Pouvez-vous publier votre plan d'exécution? –

Répondre

6

Je crois que les résultats CTE sont récupérés chaque fois. Avec une table temporaire, les résultats sont stockés jusqu'à ce qu'il soit supprimé. Cela semble expliquer les gains de performance que vous avez constatés lorsque vous êtes passé à une table temporaire.

Un autre avantage est que vous pouvez créer des index sur une table temporaire que vous ne pouvez pas faire à un cte. Je ne suis pas certain qu'il y aurait un avantage dans votre situation, mais c'est bon à savoir.

lecture connexe:

Citation du dernier lien:

requête sous-jacente de la CTE sera appelé chaque fois qu'il est référencé dans la requête suivante.

Je dirais aller avec la table temporaire. Malheureusement, l'élégance n'est pas toujours la meilleure solution.

MISE À JOUR:

Hmmm qui rend les choses plus difficiles. C'est dur pour moi de dire sans regarder votre environnement entier.

Quelques réflexions:

  • vous pouvez utiliser une procédure stockée au lieu d'une UDF (au lieu, pas à l'intérieur)?
  • Cela peut ne pas être possible mais si vous pouvez supprimer le left join de votre CTE, vous pouvez le déplacer dans une vue indexée. Si vous êtes capable de faire cela, vous pouvez voir des gains de performance même sur la table temporaire.
+0

Merci beaucoup pour ces superbes références. C'est ce que j'ai supposé alors ... Je vais devoir laisser tomber l'élégance comme vous dites, avoir cette UDF prendre 40 secondes n'est pas une option. J'espère que ça va être optimisé dans une prochaine version de SQL Server ... D'ici là, j'aurai probablement tendance à éviter les CTE ... Au moins, avec une table temporaire, je peux sentir plus dans contrôle de ce qui se passe dans les coulisses. Merci encore. –

+0

Argh ... J'avais oublié que même le multi-usage UDF ne peut pas utiliser les tables temporaires. J'ai essayé d'utiliser des variables de table à la place, mais la performance est absolument terrible ... encore pire que la version CTE ... Mon sous-ensemble de données est d'environ 10 000 lignes, mais peut aller jusqu'à 100 000 en fonction des paramètres fournis par le utilisateur. Quelles sont mes autres options considérant que j'ai * * pour renvoyer mes données en tant que table à l'appelant. Merci. –

+0

Voir ma mise à jour. Malheureusement, j'ai le sentiment que ni l'un ni l'autre ne fonctionnera pour vous. –

Questions connexes