web-dev-qa-db-fra.com

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

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 faibles millions. 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 des estimations de ligne précises vont à 1 dans l'opérateur de parallélisme (strates de répartition)? De plus, est-ce quelque chose qui devrait m'inquiéter dans cette situation particulière?

J'ai publié le plan complet sur Coller le plan .

Voici l'opération en question:

enter image description here

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

enter image description here

Puis-je rencontrer une variation de cet élément 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 même à distance proche de ce que je rencontre même s'il n'y a pas d'opérateur TOP en jeu.

12
John Eisbrener

Les plans de requête avec des filtres bitmap peuvent parfois être difficiles à lire. De l'article BOL pour les flux de répartition (accent sur 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ête utilise un filtre bitmap, le nombre de lignes dans le flux de sortie est réduit.

De plus, n 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 transitent par 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é au sein de 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_ROW contre 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:

repartition losing rows

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

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 réduite jusqu'à 1. La façon dont les lignes sont réparties entre la fonction de hachage fournit un bon indice:

row distro

Sur cette base, je soupçonne que vous avez beaucoup de valeurs répétées pour le Object1.Column21 colonne. Si les colonnes répétées ne figurent pas dans l'histogramme des statistiques pour Object4.Column19 alors 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 au temps de réponse ou aux exigences SLA alors cela ne vaut peut-être pas 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 avait de meilleures informations. Vous pouvez mettre les résultats de la jointure entre Database1.Schema1.Object10 et Database1.Schema1.Object11 dans une table temporaire et voyez si vous continuez à obtenir des jointures de boucles imbriquées. Vous pouvez changer cette jointure en LEFT OUTER JOIN afin que l'optimiseur de requêtes ne réduise pas le nombre de lignes à cette étape. Vous pouvez ajouter un MAXDOP 1 faites allusion à votre requête pour voir ce qui se passe. Vous pouvez utiliser TOP avec 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é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 lignes. 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.

9
Joe Obbish

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, CORRECTIF: 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 l'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:

6
Paul White 9

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, je regarderais 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.

0
SQLBek