Normalement, je crée des guides de plan en construisant d'abord une requête qui utilise le plan correct, et en le copiant dans la requête similaire qui ne fonctionne pas. Cependant, cela est parfois délicat, surtout si la requête n'est pas exactement la même. Quelle est la bonne façon de créer des repères de plan à partir de zéro?
SQLKiwi a mentionné l'élaboration de plans dans SSIS, existe-t-il un moyen ou un outil utile pour aider à établir un bon plan pour SQL Server?
L'instance spécifique en question est ce CTE: SQLFiddle
with cte(guid,other) as (
select newid(),1 union all
select newid(),2 union all
select newid(),3)
select a.guid, a.other, b.guid guidb, b.other otherb
from cte a
cross join cte b
order by a.other, b.other;
Y at - il QUELQUE moyen de rendre le résultat venir avec exactement 3 distinctes guid
s et pas plus? J'espère être en mesure de mieux répondre aux questions à l'avenir en incluant des guides de plan avec des requêtes de type CTE qui sont référencées plusieurs fois pour surmonter certaines bizarreries de SQL Server CTE.
la source
Réponses:
Pas aujourd'hui. Les expressions de table communes non récursives (CTE) sont traitées comme des définitions de vue en ligne et développées dans l'arborescence de requête logique à chaque endroit où elles sont référencées (tout comme les définitions de vue normales) avant l'optimisation. L'arbre logique de votre requête est:
Remarquez les deux ancres de vue et les six appels à la fonction intrinsèque
newid
avant que l'optimisation ne démarre. Néanmoins, de nombreuses personnes considèrent que l'optimiseur devrait être capable d'identifier que les sous-arborescences développées étaient à l'origine un seul objet référencé et de simplifier en conséquence. Il y a également eu plusieurs demandes Connect pour permettre la matérialisation explicite d'un CTE ou d'une table dérivée.Une implémentation plus générale aurait pour optimiseur d'envisager de matérialiser des expressions communes arbitraires pour améliorer les performances (
CASE
avec une sous-requête est un autre exemple où des problèmes peuvent survenir aujourd'hui). Microsoft Research a publié un document (PDF) à ce sujet en 2007, bien qu'il reste à ce jour non implémenté. Pour le moment, nous sommes limités à une matérialisation explicite utilisant des choses comme les variables de table et les tables temporaires.C'était juste un vœu pieux de ma part et cela allait bien au-delà de l'idée de modifier les guides de plan. Il est possible, en principe, d'écrire un outil pour manipuler directement le XML de show plan, mais sans une instrumentation d'optimiseur spécifique, l'utilisation de l'outil serait probablement une expérience frustrante pour l'utilisateur (et le développeur y penserait).
Dans le contexte particulier de cette question, un tel outil serait toujours incapable de matérialiser le contenu CTE d'une manière qui pourrait être utilisée par plusieurs consommateurs (pour alimenter les deux entrées à la jointure croisée dans ce cas). L'optimiseur et le moteur d'exécution prennent en charge les bobines multi-consommateurs, mais uniquement à des fins spécifiques - dont aucune ne pourrait être appliquée à cet exemple particulier.
Il y a ici une flexibilité raisonnable. La forme générale du plan XML est utilisée pour guider la recherche d'un plan final (bien que de nombreux attributs soient complètement ignorés, par exemple le type de partitionnement sur les échanges) et les règles de recherche normales sont également considérablement assouplies. Par exemple, l'élagage précoce des alternatives basées sur des considérations de coût est désactivé, l'introduction explicite de jointures croisées est autorisée et les opérations scalaires sont ignorées.
Il y a trop de détails pour être approfondi, mais le placement des filtres et des scalaires de calcul ne peut pas être forcé, et les prédicats du formulaire
column = value
sont généralisés de sorte qu'un plan contenantX = 1
ouX = @X
peut être appliqué à une requête contenantX = 502
ouX = @Y
. Cette flexibilité particulière peut grandement aider à trouver un plan naturel à forcer.Dans l'exemple spécifique, l'union constante peut toujours être implémentée en tant que balayage constant; le nombre d'entrées dans l'Union Tout n'a pas d'importance.
la source
Il n'y a aucun moyen (versions SQL Server jusqu'en 2012) de réutiliser un seul spool pour les deux occurrences du CTE. Les détails peuvent être trouvés dans la réponse de SQLKiwi. Vous trouverez ci - dessous deux façons de matérialiser deux fois le CTE, ce qui est inévitable pour la nature de la requête. Les deux options entraînent un nombre net de guides distincts de 6.
Le lien entre le commentaire de Martin et le site de Quassnoi sur un blog sur le plan guidant un CTE a été une inspiration partielle pour cette question. Il décrit un moyen de matérialiser un CTE aux fins d'une sous-requête corrélée, qui n'est référencée qu'une seule fois bien que la corrélation puisse entraîner son évaluation plusieurs fois. Cela ne s'applique pas à la requête dans la question.
Option 1 - Guide du plan
En prenant des indices de la réponse de SQLKiwi, j'ai réduit le guide à un strict minimum qui fera toujours le travail, par exemple, les
ConstantScan
nœuds ne répertorient que 2 opérateurs scalaires qui peuvent suffisamment s'étendre à n'importe quel nombre.Option 2 - Analyse à distance
En augmentant le coût de la requête et en introduisant un scan à distance, le résultat est matérialisé.
la source
Sérieusement, vous ne pouvez pas découper les plans d'exécution xml à partir de zéro. Les créer à l'aide de SSIS est de la science-fiction. Oui, c'est tout XML, mais ils proviennent d'univers différents. En regardant le blog de Paul sur ce sujet , il dit "beaucoup dans la façon dont SSIS le permet ..." alors vous avez peut-être mal compris? Je ne pense pas qu'il dit "utilisez SSIS pour créer des plans" mais plutôt "ne serait-il pas formidable de pouvoir créer des plans en utilisant une interface glisser-déposer comme SSIS". Peut-être, pour une requête très simple, vous pourriez à peu près gérer cela, mais c'est un tronçon, peut-être même une perte de temps. On pourrait dire un travail chargé.
Si je crée un plan pour un indice ou un guide de plan UTILISATION, j'ai quelques approches. Par exemple, je peux supprimer des enregistrements des tables (par exemple sur une copie de la base de données) pour influencer les statistiques et encourager l'optimiseur à prendre une décision différente. J'ai également utilisé des variables de table au lieu de toutes les tables de la requête, de sorte que l'optimiseur pense que chaque table contient 1 enregistrement. Ensuite, dans le plan généré, remplacez toutes les variables de table par les noms de table d'origine et échangez-les en tant que plan. Une autre option serait d'utiliser l'option WITH STATS_STREAM de UPDATE STATISTICS pour usurper les statistiques qui est la méthode utilisée lors du clonage de copies de bases de données uniquement statistiques, par exemple
J'ai passé du temps à bricoler des plans d'exécution xml dans le passé et j'ai trouvé qu'en fin de compte, SQL va juste "je ne l'utilise pas" et exécute la requête comme il veut de toute façon.
Pour votre exemple spécifique, je suis sûr que vous savez que vous pouvez utiliser set rowcount 3 ou TOP 3 dans la requête pour obtenir ce résultat, mais je suppose que ce n'est pas votre point. La bonne réponse serait vraiment: utilisez une table temporaire. Je voterais pour:) Pas une bonne réponse serait "passer des heures voire des jours à découper votre propre plan d'exécution XML personnalisé où vous essayez de tromper l'optimiseur en faisant une bobine paresseuse pour le CTE qui pourrait même ne pas fonctionner de toute façon, aurait l'air intelligent mais serait également impossible à maintenir ".
Ne pas essayer de ne pas être constructif là-bas, juste mon avis - j'espère que cela aide.
la source
Enfin, dans SQL 2016 CTP 3.0, il existe un moyen, une sorte de:)
En utilisant l'indicateur de trace et les événements étendus détaillés par Dmitry Pilugin ici , vous pouvez (quelque peu arbitrairement) repérer trois guides uniques des étapes intermédiaires de l'exécution de la requête.
NB Ce code n'est PAS destiné à la production ou à une utilisation sérieuse en ce qui concerne le forçage de plan CTE, simplement un regard léger sur un nouveau drapeau de trace et une manière différente de faire les choses:
Testé sur la version (CTP3.2) - 13.0.900.73 (x64), juste pour le plaisir.
la source
J'ai trouvé que traceflag 8649 (forcer le plan parallèle) induisait ce comportement pour la colonne guid de gauche sur mes instances 2008, R2 et 2012. Je n'avais pas besoin d'utiliser l'indicateur sur SQL 2005 où le CTE s'est comporté correctement. J'ai essayé d'utiliser le plan généré dans SQL 2005 dans les instances supérieures, mais il n'a pas été validé.
Soit en utilisant l'indice, en utilisant un guide de plan incluant l'indice ou en utilisant le plan généré par la requête avec l'indice dans un PLAN D'UTILISATION, etc., tout a fonctionné.
la source