Pourquoi l'opérateur de parallélisme (flux de répartition) réduirait-il les estimations de lignes à 1?

12

J'utilise SQL Server 2012 Enterprise. J'ai rencontré un plan SQL qui présente un comportement que je ne trouve pas entièrement intuitif. Après une opération de balayage d'index parallèle intense, une opération de parallélisme (flux de répartition) se produit, mais elle tue les estimations de ligne renvoyées par le balayage d'index (Object10.Index2), réduisant l'estimation à 1. J'ai fait quelques recherches, mais n'ont rien trouvé qui explique ce comportement. La requête est assez simple, bien que chacune des tables contienne des enregistrements dans les millions bas. Cela fait partie d'un processus de chargement DWH et cet ensemble de données intermédiaires est touché plusieurs fois tout au long, mais la question que j'ai est liée aux estimations de ligne en particulier. Quelqu'un peut-il expliquer pourquoi les estimations de ligne précises vont à 1 dans l'opérateur de parallélisme (strates de répartition)? Aussi,

J'ai publié le plan complet pour coller le plan .

Voici l'opération en question:

entrez la description de l'image ici

Inclure l'arborescence du plan au cas où cela ajouterait plus de contexte:

entrez la description de l'image ici

Puis-je rencontrer une variante de cet article Connect déposé par Paul White (explication plus approfondie sur son blog ici )? Au moins, c'est la seule chose que j'ai trouvée qui semble être même à distance proche de ce que je rencontre même s'il n'y a pas d'opérateur TOP en jeu.

John Eisbrener
la source

Réponses:

9

Les plans de requête avec des filtres bitmap peuvent parfois être difficiles à lire. Extrait de l'article BOL pour les flux de répartition (soulignement le mien):

L'opérateur Repartition Streams consomme plusieurs flux et produit plusieurs flux d'enregistrements. Le contenu et le format de l'enregistrement ne sont pas modifiés. Si l'optimiseur de requêtes utilise un filtre bitmap, le nombre de lignes dans le flux de sortie est réduit.

De plus, un article sur les filtres bitmap est également utile:

Lors de l'analyse d'un plan d'exécution contenant un filtrage bitmap, il est important de comprendre comment les données circulent dans le plan et où le filtrage est appliqué. Le filtre bitmap et le bitmap optimisé sont créés du côté de l'entrée de génération (la table de dimension) d'une jointure de hachage; cependant, le filtrage réel est généralement effectué dans l'opérateur de parallélisme, qui se trouve du côté de l'entrée de sonde (la table de faits) de la jointure de hachage. Cependant, lorsque le filtre bitmap est basé sur une colonne entière, le filtre peut être appliqué directement à l'opération de table ou d'indexation initiale plutôt qu'à l'opérateur de parallélisme. Cette technique est appelée optimisation en ligne.

Je crois que c'est ce que vous observez avec votre requête. Il est possible de proposer une démo relativement simple pour montrer un opérateur de flux de répartition réduisant une estimation de cardinalité, même lorsque l'opérateur bitmap est IN_ROWcontre la table de faits. Préparation des données:

create table outer_tbl (ID BIGINT NOT NULL);

INSERT INTO outer_tbl WITH (TABLOCK)
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values;

create table inner_tbl_1 (ID BIGINT NULL);
create table inner_tbl_2 (ID BIGINT NULL);

INSERT INTO inner_tbl_1 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

INSERT INTO inner_tbl_2 WITH (TABLOCK)
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) / 2000000 - 2) NUM
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Voici une requête que vous ne devez pas exécuter:

SELECT *
FROM outer_tbl o
INNER JOIN inner_tbl_1 i ON o.ID = i.ID
INNER JOIN inner_tbl_2 i2 ON o.ID = i2.ID
OPTION (HASH JOIN, QUERYTRACEON 9481, QUERYTRACEON 8649);

J'ai téléchargé le plan . Jetez un œil à l'opérateur près de inner_tbl_2:

répartition des lignes perdantes

Vous pouvez également trouver utile le deuxième test dans Hash Joins on Nullable Columns de Paul White.

Il existe certaines incohérences dans la façon dont la réduction des lignes est appliquée. Je n'ai pu le voir que dans un plan avec au moins trois tables. Cependant, la réduction des lignes attendues semble raisonnable avec la bonne distribution des données. Supposons que la colonne jointe dans la table de faits ait de nombreuses valeurs répétées qui ne sont pas présentes dans la table de dimension. Un filtre bitmap peut éliminer ces lignes avant qu'elles n'atteignent la jointure. Pour votre requête, l'estimation est entièrement réduite à 1. La façon dont les lignes sont réparties entre la fonction de hachage fournit un bon indice:

distribution de ligne

Sur cette base, je soupçonne que vous avez beaucoup de valeurs répétées pour la Object1.Column21colonne. Si les colonnes répétées ne se trouvent pas dans l'histogramme des statistiques, Object4.Column19alors SQL Server pourrait obtenir une estimation de cardinalité très erronée.

Je pense que vous devriez être préoccupé par le fait qu'il pourrait être possible d'améliorer les performances de la requête. Bien sûr, si la requête répond aux exigences de temps de réponse ou de SLA, cela peut ne pas valoir la peine d'être approfondi. Cependant, si vous souhaitez approfondir votre recherche, vous pouvez faire certaines choses (autres que la mise à jour des statistiques) pour savoir si l'optimiseur de requêtes choisirait un meilleur plan s'il disposait de meilleures informations. Vous pouvez placer les résultats de la jointure entre Database1.Schema1.Object10et Database1.Schema1.Object11dans une table temporaire et voir si vous continuez à obtenir des jointures de boucles imbriquées. Vous pouvez remplacer cette jointure par un LEFT OUTER JOINafin que l'optimiseur de requête ne réduise pas le nombre de lignes à cette étape. Vous pouvez ajouter un MAXDOP 1indice à votre requête pour voir ce qui se passe. Vous pourriez utiliserTOPavec une table dérivée pour forcer la jointure à durer en dernier, ou vous pouvez même commenter la jointure à partir de la requête. J'espère que ces suggestions suffisent pour vous aider à démarrer.

En ce qui concerne l' élément de connexion dans la question, il est extrêmement peu probable qu'il soit lié à votre question. Ce problème n'a pas à voir avec de mauvaises estimations de ligne. Cela a à voir avec une condition de concurrence critique dans le parallélisme qui provoque le traitement d'un trop grand nombre de lignes dans le plan de requête en arrière-plan. Ici, il semble que votre requête ne fasse aucun travail supplémentaire.

Joe Obbish
la source
6

Le problème principal ici est une mauvaise estimation de la cardinalité pour le résultat de la première jointure. Cela peut se produire pour de nombreuses raisons, mais il s'agit le plus souvent de statistiques obsolètes ou d'un certain nombre de prédicats de jointure corrélés, que le modèle par défaut de l'optimiseur suppose indépendants.

Dans ce dernier cas, FIX: performances médiocres lorsque vous exécutez une requête qui contient des prédicats ET corrélés dans SQL Server 2008 ou SQL Server 2008 R2 ou SQL Server 2012 peut être pertinent à l'aide de l'indicateur de trace pris en charge 4137. Vous pouvez également essayer la requête avec indicateur de trace 4199 pour activer les correctifs de l'optimiseur et / ou 2301 pour activer les extensions de modélisation. C'est difficile à savoir sur la base d'un plan anonymisé.

La présence du bitmap n'affecte pas directement l'estimation de cardinalité de la jointure, mais elle rend son effet visible plus tôt en appliquant une réduction de semi-jointure précoce. Sans le bitmap, l'estimation de cardinalité pour la première jointure serait la même et le reste du plan serait toujours optimisé en conséquence.

Si vous êtes curieux, sur un système de test, vous pouvez désactiver les bitmaps pour la requête avec l'indicateur de trace 7498. Vous pouvez également désactiver les bitmaps optimisés (pris en compte par l'optimiseur et affectant les estimations de cardinalité), en les remplaçant par des bitmaps post-optimisation (non pris en compte par l'optimiseur, aucun effet sur la cardinalité) avec une combinaison d'indicateurs de trace 7497 et 7498. Ni l'un ni l'autre n'est documenté ou pris en charge pour une utilisation sur un système de production, mais ils produisent des plans que l'optimiseur pourrait considérer normalement, et peuvent donc être forcés avec un guide de plan.

Rien de tout cela ne résoudra le problème central de la mauvaise estimation pour la première jointure comme indiqué ci-dessus, donc je ne fais que le mentionner pour des raisons d'intérêt.

Pour en savoir plus sur les bitmaps et les jointures de hachage:

Paul White 9
la source
0

vous a répondu sur Twitter. J'ai regardé le XML joint et je vois un parallélisme déséquilibré. 1 thread a presque toutes les lignes réelles, contrairement à la plupart des autres. Cela crie un parallélisme déséquilibré. Par conséquent, j'examinerais la valeur clé / jointure et ses statistiques et cardinalités respectives.

Selon votre autre idée, je ne suis pas certain que l'élément Connect s'applique, car votre plan collé ne contient TOP nulle part que j'ai vu.

SQLBek
la source