Преобразование VARCHAR в VARBINARY

17

Я веду журнал дорогостоящих выполняемых запросов вместе с их планами запросов в таблице, которая позволяет нам отслеживать тенденции в производительности и выявлять области, требующие оптимизации.

Однако дошло до того, что планы запросов занимают слишком много места (поскольку мы храним весь план для каждого запроса).

Поэтому я пытаюсь нормализовать существующие данные, извлекая QueryPlanHash и QueryPlan в другую таблицу.

CREATE TABLE QueryPlans
(
    QueryPlanHash VARBINARY(25),
    QueryPlan XML,
    CONSTRAINT PK_QueryPlans PRIMARY KEY
    (
      QueryPlanHash
    )
);

Поскольку определение query_plan_hashin sys.dm_exec_query_statsявляется двоичным полем (и я буду регулярно вставлять новые данные), я использовал VARBINARYдля типа данных в моей новой таблице.

Тем не менее, вставка ниже не удается ...

INSERT INTO QueryPlans
    ( QueryPlanHash, QueryPlan )
SELECT queryplanhash, queryplan
FROM
(
    SELECT 
      p.value('(./@QueryPlanHash)[1]', 'varchar(20)') queryplanhash,
      QueryPlan,
      ROW_NUMBER() OVER (PARTITION BY p.value('(./@QueryPlanHash)[1]', 'varchar(20)') ORDER BY DateRecorded) rownum
    FROM table
    CROSS APPLY QueryPlan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple[@QueryPlanHash]') t(p)
) data
WHERE rownum = 1

.... с ошибкой

Implicit conversion from data type varchar to varbinary is not allowed. Use the CONVERT function to run this query.

Проблема заключается в том, что хэши плана запросов уже находятся в двоичном формате, однако сохраняются как VARCHAR в плане запросов XML, например

0x9473FBCCBC01AFE

и CONVERT to BINARY дает совершенно другое значение

0x3078393437334642434342433031414645

Я попытался изменить определение значения в XQuery select на двоичное, но потом не вернуло никаких значений.

Как извлечь значение из 0x9473FBCCBC01AFEплана XML-запроса как VARBINARY, а не как VARCHAR?

Марк Синкинсон
источник

Ответы:

28

Вам нужно использовать определенный стиль, если вы ожидаете, что при преобразовании из строки сохраните одно и то же двоичное значение. В противном случае SQL Server пытается закодировать строку таким же образом он будет закодировать 'bob'или 'frank'.

Тем не менее, ваша входная строка не выглядит правильно - пропущен байт или слишком много байт. Это отлично работает, если я отбросить трейлинг E:

SELECT CONVERT(VARBINARY(25), '0x9473FBCCBC01AF', 1);
------------ the ,1 is important ---------------^^^

Результат является двоичным:

----------------
0x9473FBCCBC01AF
Аарон Бертран
источник
1
Ах, это ,1то, чего мне не хватало. Это было проще, чем я ожидал! Благодарность!
Марк Синкинсон
Не уверен насчет пропущенного / лишнего байта. В 2666 записях, которые у меня есть, есть 183, которые терпят неудачуTRY_CONVERT
Марк Синкинсон
Может потребоваться добавить символ (скажем, 0) к любой строке с количеством нечетных символов. Это меняет значение, но всегда должно менять одно и то же значение одинаково (и я не подозреваю, что у вас будут какие-либо коллизии с или без 0).
Аарон Бертран
Это не ошибка? Аргумент queryplanhash в xml явно установлен на это значение ... Конечно, a TRY_CONVERTa BINARYне должен возвращатьсяNULL
Марк Синкинсон
От сравнения значений, сохраненных в моей таблице, до xml, на самом деле отсутствует начальный 0. Таким образом, значение должно быть 0x09473FBCCBC01AF. Я могу исправить это с помощью простой ЗАМЕНЫ, но я уверен, что это ошибка ...
Марк Синкинсон
0

Как извлечь значение 0x9473FBCCBC01AFE из плана XML-запроса как VARBINARY, а не VARCHAR?

Я столкнулся с чем-то подобным, используя HeidiSQL для запросов к таблицам CASD , и решил с помощью fn_varbintohexstr () , вот так:

SELECT master.dbo.fn_varbintohexstr(table.hexfield) FROM table;

В HeidiSQL значение было неправильным, например «0x3F3F3F3F3F3F3F3F», и стало правильным, например «0x158B1DB75616484695684007CE98E21C».

OBS: работает с MSSQL 2008! Надеюсь, это поможет!

MMJ
источник
2
Обратите внимание на предостережения по использованию, fn_varbintohexstr() упомянутые здесь .
Эрик