SQL Server Query Plan XML: QueryPlanHash Length

11

ACTUALIZACIÓN: Esto definitivamente es un error. Para más detalles vea este artículo de conexión .

Mientras probaba algunos cambios en sp_BlitzCache (divulgación completa, soy uno de los autores), me encontré con lo que pensé que era un error en nuestro código.

En un momento, estamos haciendo coincidir el hash del plan de consulta para obtener el costo de la consulta. Hacemos eso así:

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

Esto, por lo que he visto, ha funcionado. Sin embargo, en un caso extraño, la subcadena en el XML arrojaba un NULLvalor, y el plan mostraba un costo de 0, a pesar de ser bastante alto.

Al profundizar en el plan de ejecución (divulgación completa, trabajo para la empresa que aloja Paste The Plan), noté que el hash del plan de consulta para el hash de un problema tenía 17 caracteres, mientras que el resto son 18. Aquí hay ejemplos:

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

Query Plan Hash aparece en la lista como BINARY 8: presumiblemente, esto siempre debe tener la misma longitud, pero ¿qué sabe un tipo como yo sobre los valores binarios?

Jugando un poco con XQuery, descubrí que al cambiar la subcadena para comenzar en la segunda posición, obtendría un valor de hash válido (aunque incorrecto).

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

Nueces

Estoy ejecutando SQL Server 2016, SP1 (13.0.4001).

¿Alguien se ha encontrado con esto antes?

¿Son 17 caracteres una longitud válida para un BINARY 8valor?

¿Esto parece un error que debería obtener un elemento Connect?

Erik Darling
fuente

Respuestas:

11

Creo que esto está sucediendo porque ese hash es un número impar de caracteres. Un válido VARBINARYtendrá que tener un número par de "pares" para representar correctamente los datos. Entonces ... deberías poder resolver esto eliminando el 0x, poniendo un '0' al principio, agarrando los 18 caracteres correctos, y luego lanzándolo a VARBINARY.

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

Si desea algo más robusto, buena suerte, porque necesitaría dividir entre 2 como un número entero, y obtener el módulo de 2, y luego "hacer lo correcto" para determinar qué tan grandes deberían ser sus datos.

Jeremiah Peschka
fuente