SQL Server 쿼리 계획 XML : QueryPlanHash 길이


11

업데이트 : 이것은 분명히 버그입니다. 자세한 내용은 이 연결 항목을 참조하십시오 .

sp_BlitzCache (전체 공개, 필자는 필자 중 하나)에 대한 일부 변경 사항을 테스트하는 동안 코드에서 버그라고 생각한 부분을 발견했습니다.

어느 시점에서 쿼리 비용을 얻기 위해 쿼리 계획 해시를 일치시킵니다. 우리는 그렇게 그렇게합니다 :

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

내가 본 한, 이것은 효과가있었습니다. 그러나 이상한 경우에는 XML의 하위 문자열이 NULL값 을 던지고 있었지만 계획은 다소 높지만 비용은 0이었습니다.

으로 파고 실행 계획 (전체 공개는 호스트 계획을 붙여 넣기하는 회사 I의 작품), I는 쿼리 계획 해시가 하나의 문제 해시의 나머지 (18) 다음은 예입니다 동안, 17 자였다 것으로 나타났습니다 :

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

견과류

SQL Server 2016, SP1 (13.0.4001)을 실행하고 있습니다.

누구든지 전에이 문제를 겪었습니까?

BINARY 8값의 길이는 17 자 입니까?

연결 항목을 가져와야하는 버그처럼 보입니까?

답변:


11

하나의 해시가 홀수 문자이기 때문에 이것이 일어나고 있다고 생각합니다. 유효한 VARBINARY데이터를 올바르게 나타내려면 짝수의 "쌍"이 있어야합니다. 따라서 ...를 제거 0x하고 처음에 '0'을 넣고 오른쪽 18자를 붙인 다음에 캐스팅하면 이 문제를 해결할 수 있습니다 VARBINARY.

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

더 강력하고 행운이 필요한 것을 원한다면 정수로 2로 나누고 모듈로 2를 구한 다음 "올바른 일을 수행"하여 데이터의 크기를 파악해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.