SQL Server 查询计划 XML:QueryPlanHash 长度

Eri*_*ing 11 xml sql-server datatypes execution-plan

更新:这绝对是一个错误。有关完整详细信息,请参阅此连接项

在测试sp_BlitzCache 的一些更改(完全公开,我是作者之一)时,我发现了我认为是我们代码中的错误。

在某一时刻,我们匹配查询计划哈希以获得查询成本。我们这样做:

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

就我所见,这已经奏效了。然而,在一个奇怪的情况下,XML 中的子字符串抛出一个NULL值,并且计划显示成本为 0,尽管它相当高。

深入研究执行计划(完全公开,我为托管 Paste The Plan 的公司工作),我注意到一个问题哈希的查询计划哈希长度为 17 个字符,而其余为 18 个字符。以下是示例:

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

查询计划哈希上市BINARY 8-想必这应该是相同的长度,但到底是什么像我这样的人了解二进制值?

稍微使用 XQuery,我发现通过将子字符串更改为从第二个位置开始,它会得出一个有效(尽管不正确)的哈希值。

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);
Run Code Online (Sandbox Code Playgroud)

坚果

我正在运行 SQL Server 2016 SP1 (13.0.4001)。

有没有人遇到过这个?

17 个字符是一个BINARY 8值的有效长度吗?

这看起来像一个应该获得 Connect 项目的错误吗?

Jer*_*hka 11

我认为这是因为一个哈希是奇数个字符。一个有效VARBINARY的将需要有偶数个“对”才能正确表示数据。所以......你应该能够通过删除0x,在开头放一个“0”,抓住正确的 18 个字符,然后将它转换为VARBINARY.

CONVERT(VARBINARY(MAX), RIGHT('0' + SUBSTRING('0xED4F225CC0E97E5', 3, 20), 18), 2)
Run Code Online (Sandbox Code Playgroud)

如果你想要更健壮的东西,祝你好运,因为你需要除以 2 作为一个整数,得到 2 的模数,然后“做正确的事”来计算你的数据应该有多大。