Plan de requête SQL Server XML: longueur de QueryPlanHash

11

MISE À JOUR: Ceci est définitivement un bug. Pour plus de détails, consultez cet élément Connect .

En testant certaines modifications de sp_BlitzCache (divulgation complète, je suis l'un des auteurs), je suis tombé sur ce que je pensais être un bogue dans notre code.

À un moment donné, nous faisons correspondre le hachage du plan de requête pour obtenir le coût de la requête. Nous faisons cela à peu près comme ceci:

statement.value('sum(/p:StmtSimple[xs:hexBinary(substring(@QueryHash, 3)) =
    xs:hexBinary(sql:column("b.QueryHash"))]/@StatementSubTreeCost)', 'float')

Pour autant que je sache, cela a fonctionné. Cependant, dans un cas étrange, la sous-chaîne dans le XML générait une NULLvaleur, et le plan affichait un coût de 0, bien qu'il soit plutôt élevé.

En fouillant dans le plan d'exécution (divulgation complète, je travaille pour la société qui héberge Paste The Plan), j'ai remarqué que le hachage du plan de requête pour le hachage à un problème comptait 17 caractères, tandis que les autres sont 18. Voici des exemples:

QueryPlanHash = "0x4410B0CA640CDA89"
QueryPlanHash = "0x2262FEA4CE645569" 
QueryPlanHash = "0xED4F225CC0E97E5" - Problème!
QueryPlanHash = "0xBF878EEE6DB955EA"
QueryPlanHash = "0x263B53BC8C14A452"
QueryPlanHash = "0x89F5F146CF4B476F"
QueryPlanHash = "0xEF47EA40805C8961"
QueryPlanHash = "0xB7BE27D6E43677A5"
QueryPlanHash = "0x815C54EC43A6A6E9"

Query Plan Hash est répertorié comme BINARY 8- sans doute cela devrait toujours être la même longueur, mais qu'est-ce qu'un gars comme moi sait sur les valeurs binaires?

En jouant un peu avec le XQuery, j'ai trouvé qu'en changeant la sous-chaîne pour commencer à la deuxième position, elle aboutirait à une valeur de hachage valide (quoique incorrecte).

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p)
SELECT   
        QueryPlanCost = statement.value('sum(/p:StmtSimple/@StatementSubTreeCost)', 'float'),
        **q.n.value('substring(@QueryPlanHash, 2)', 'BINARY(8)')**
FROM    #statements s
CROSS APPLY s.statement.nodes('/p:StmtSimple') AS q(n)
OPTION(RECOMPILE);

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p)
SELECT   
        QueryPlanCost = statement.value('sum(/p:StmtSimple/@StatementSubTreeCost)', 'float'),
        **q.n.value('substring(@QueryPlanHash, 3)', 'BINARY(8)')**
FROM    #statements s
CROSS APPLY s.statement.nodes('/p:StmtSimple') AS q(n)
OPTION(RECOMPILE);

Des noisettes

J'exécute SQL Server 2016, SP1 (13.0.4001).

Quelqu'un a-t-il déjà rencontré cela?

17 caractères sont-ils une longueur valide pour une BINARY 8valeur?

Cela ressemble-t-il à un bogue qui devrait obtenir un élément Connect?

Erik Darling
la source

Réponses:

11

Je pense que cela se produit parce que ce hachage est un nombre impair de caractères. Un valide VARBINARYva devoir avoir un nombre pair de "paires" pour représenter correctement les données. Donc ... vous devriez être en mesure de résoudre ce problème en supprimant le 0x, en mettant un «0» au début, en saisissant les 18 bons caractères, puis en le lançant VARBINARY.

CONVERT(VARBINARY(MAX), RIGHT('0' + SUBSTRING('0xED4F225CC0E97E5', 3, 20), 18), 2)

Si vous voulez quelque chose de plus robuste, bonne chance, car vous devrez diviser par 2 en tant qu'entier, obtenir le module de 2, puis "faire la bonne chose" pour déterminer la taille de vos données.

Jeremiah Peschka
la source