SQL Server-Abfrageplan XML: QueryPlanHash-Länge

11

UPDATE: Dies ist definitiv ein Fehler. Ausführliche Informationen finden Sie in diesem Verbindungselement .

Beim Testen einiger Änderungen an sp_BlitzCache (vollständige Offenlegung, ich bin einer der Autoren) bin ich auf einen Fehler in unserem Code gestoßen .

An einem Punkt stimmen wir mit dem Abfrageplan-Hash überein, um die Abfragekosten zu erhalten. Wir machen das ungefähr so:

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

Soweit ich gesehen habe, hat dies funktioniert. In einem seltsamen Fall warf der Teilstring im XML jedoch einen NULLWert aus, und der Plan zeigte Kosten von 0 an, obwohl er ziemlich hoch war.

Beim Durchsuchen des Ausführungsplans (vollständige Offenlegung, ich arbeite für das Unternehmen, das Paste The Plan hostet) stellte ich fest, dass der Abfrageplan-Hash für den einen Problem-Hash 17 Zeichen lang war, während der Rest 18 Zeichen umfasst. Hier einige Beispiele:

QueryPlanHash = "0x4410B0CA640CDA89"
QueryPlanHash = "0x2262FEA4CE645569" 
QueryPlanHash = "0xED4F225CC0E97E5" - Problem!
QueryPlanHash = "0xBF878EEE6DB955EA"
QueryPlanHash = "0x263B53BC8C14A452"
QueryPlanHash = "0x89F5F146CF4B476F"
QueryPlanHash = "0xEF47EA40805C8961"
QueryPlanHash = "0xB7BE27D6E43677A5"
QueryPlanHash = "0x815C54EC43A6A6E9"

Query Plan Hash wird als aufgeführtBINARY 8 - vermutlich sollte dies immer die gleiche Länge haben, aber was weiß ein Typ wie ich über Binärwerte?

Als ich ein wenig mit der XQuery spielte, stellte ich fest, dass durch Ändern der Teilzeichenfolge an der zweiten Position ein gültiger (wenn auch falscher) Hashwert erhalten würde.

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);

Nüsse

Ich verwende SQL Server 2016, SP1 (13.0.4001).

Hat jemand schon einmal darauf gestoßen?

Sind 17 Zeichen eine gültige Länge für einen BINARY 8Wert?

Sieht dies wie ein Fehler aus, der ein Connect-Element erhalten sollte?

Erik Darling
quelle

Antworten:

11

Ich denke, das passiert, weil dieser eine Hash eine ungerade Anzahl von Zeichen ist. Ein Gültiger VARBINARYmuss eine gerade Anzahl von "Paaren" haben, um die Daten korrekt darzustellen. Also ... Sie sollten in der Lage sein, dieses Problem zu lösen, indem Sie die entfernen 0x, am Anfang eine '0' setzen, die richtigen 18 Zeichen auswählen und sie dann auf werfen VARBINARY.

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

Wenn Sie etwas Robusteres wollen, viel Glück, denn Sie müssten als Ganzzahl durch 2 teilen und das Modulo 2 erhalten und dann "das Richtige tun", um herauszufinden, wie groß Ihre Daten sein sollten.

Jeremiah Peschka
quelle