Isso é definitivamente um bug. Os detalhes estavam no antigo site do Connect e não estão mais disponíveis, pois foram retirados em favor de um número indeterminado de outras soluções, tanto de terceiros quanto de terceiros.
Ao testar algumas mudanças no sp_BlitzCache (divulgação completa, sou um dos autores), me deparei com o que pensei ser um bug em nosso código.
Em um ponto, estamos combinando o Hash do plano de consulta para obter o custo da consulta. Fazemos isso mais ou menos assim: statement.value('sum(/p:StmtSimple[xs:hexBinary(substring(@QueryHash, 3)) = xs:hexBinary(sql:column("b.QueryHash"))]/@ StatementSubTreeCost)', 'float')
Isso tem, tanto quanto eu tenho visto, funcionou. No entanto, em um caso estranho, a substring no XML estava lançando um NULL
valor e o plano estava mostrando um custo de 0, apesar de ser bastante alto.
Investigando o plano de execução , notei que o Hash do Plano de Consulta para o hash do problema tinha 17 caracteres, enquanto o restante tinha 18. Aqui estão alguns exemplos:
QueryPlanHash="0x4410B0CA640CDA89" QueryPlanHash="0x2262FEA4CE645569" QueryPlanHash="0xED4F225CC0E97E5" -- Problema! QueryPlanHash="0xBF878EEE6DB955EA" QueryPlanHash="0x263B53BC8C14A452" QueryPlanHash="0x89F5F146CF4B476F" QueryPlanHash="0xEF47EA40805C8961" QueryPlanHash="0xB7BE27D6E43677A5" QueryPlanHash="0x815C54EC43A6A6E9"
O Query Plan Hash está listado como binary 8
-- presumivelmente, deve ter sempre o mesmo tamanho, mas o que um cara como eu sabe sobre valores binários?
Brincando um pouco com o XQuery, descobri que, alterando a substring para iniciar na segunda posição, ela geraria um valor de hash válido (embora incorreto).
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);
Estou executando o SQL Server 2016, SP1 (13.0.4001).
Alguém já se deparou com isso antes?
17 caracteres é um comprimento válido para um binary 8
valor?
Eu acho que isso está acontecendo porque esse hash é um número ímpar de caracteres. Um válido
VARBINARY
precisará ter um número par de "pares" para representar corretamente os dados. Então ... você deve ser capaz de resolver isso removendo o0x
, colocando um '0' no início, pegando os 18 caracteres corretos e depois lançando-o paraVARBINARY
.Se você quiser algo mais robusto, boa sorte, porque você precisaria dividir por 2 como um número inteiro e obter o módulo de 2 e depois "fazer a coisa certa" para descobrir o tamanho dos seus dados.