План запроса 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, хотя она была довольно высокой.

Углубившись в план выполнения (полное раскрытие, я работаю в компании, в которой работает Paste The Plan), я заметил, что хэш плана запроса для одного хеш-задачи имеет длину 17 символов, а остальные - 18. Вот примеры:

QueryPlanHash = "0x4410B0CA640CDA89"
QueryPlanHash = "0x2262FEA4CE645569" 
QueryPlanHash = "0xED4F225CC0E97E5" - Проблема!
QueryPlanHash = "0xBF878EEE6DB955EA"
QueryPlanHash = "0x263B53BC8C14A452"
QueryPlanHash = "0x89F5F146CF4B476F"
QueryPlanHash = "0xEF47EA40805C8961"
QueryPlanHash = "0xB7BE27D6E43677A5"
QueryPlanHash = "0x815C54EC43A6A6E9"

План запроса Hash указан как 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 с пакетом обновления 1 (13.0.4001).

Кто-нибудь сталкивался с этим раньше?

Является ли 17 символов допустимой длиной для BINARY 8значения?

Похоже ли это на ошибку, которая должна получить элемент Connect?

Эрик Дарлинг
источник

Ответы:

11

Я думаю, что это происходит потому, что один хеш - нечетное количество символов. У действительного VARBINARYдолжно быть четное количество «пар», чтобы правильно представлять данные. Итак ... вы должны быть в состоянии решить эту проблему, удалив 0x, поставив '0' в начале, выбрав правильные 18 символов, а затем приведя его к VARBINARY.

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

Если вы хотите что-то более надежное, удачи, потому что вам нужно разделить на 2 как целое число и получить по модулю 2, а затем «поступить правильно», чтобы выяснить, насколько большими должны быть ваши данные.

Иеремия Пешка
источник