Conversione di un VARCHAR in VARBINARY


17

Ho tenuto un registro delle query costose in esecuzione, insieme ai loro piani di query, in una tabella per consentirci di monitorare le tendenze nelle prestazioni e identificare le aree che devono essere ottimizzate.

Tuttavia, è arrivato al punto in cui i piani di query occupano troppo spazio (poiché stiamo memorizzando l'intero piano su ogni query).

Sto quindi tentando di normalizzare i dati esistenti estraendo QueryPlanHash e QueryPlan in un'altra tabella.

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

Poiché la definizione di query_plan_hashin sys.dm_exec_query_statsè un campo binario (e inserirò regolarmente nuovi dati), stavo usando VARBINARYper il tipo di dati nella mia nuova tabella.

Tuttavia, l'inserto seguente non riesce ...

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

.... con l'errore

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

Il problema è che gli hash del piano di query sono già in formato binario, tuttavia memorizzati come VARCHAR nel piano di query XML, ad es.

0x9473FBCCBC01AFE

e CONVERT a BINARY dà un valore completamente diverso

0x3078393437334642434342433031414645

Ho provato a cambiare la definizione del valore in XQuery selezionare su binario, ma poi non ha restituito alcun valore.

Come estrarrei il valore di 0x9473FBCCBC01AFEun piano di query XML come un VARBINARY, piuttosto che un VARCHAR?

Risposte:


28

È necessario utilizzare uno stile specifico quando si prevede di mantenere lo stesso valore binario durante la conversione da una stringa. In caso contrario, SQL Server tenta di codificare la stringa nello stesso modo in cui codificherà 'bob'o 'frank'.

Detto questo, la stringa di input non sembra corretta: manca un byte o un byte in eccesso. Funziona bene se trascino il finale E:

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

Il risultato è binario:

----------------
0x9473FBCCBC01AF

1
Ah, ,1era quello che mi mancava. È stato più facile di quanto mi aspettassi! Grazie!
Mark Sinkinson,

Non sono sicuro del byte mancante / extra. Nei 2666 dischi che ho, ce ne sono 183 che fallisconoTRY_CONVERT
Mark Sinkinson,

Potrebbe essere necessario aggiungere un carattere (diciamo, 0) a qualsiasi stringa con un conteggio di caratteri dispari. Questo cambia il valore, ma dovrebbe sempre cambiare lo stesso valore allo stesso modo (e non sospetto che ci saranno collisioni con o senza lo 0).
Aaron Bertrand

Non è un bug? Il queryplanhash nell'xml è esplicitamente impostato su quel valore ... Sicuramente un TRY_CONVERTa un BINARYnon dovrebbe tornareNULL
Mark Sinkinson

Dal confronto dei valori salvati nella mia tabella con l'xml, in realtà manca uno 0 iniziale. Quindi il valore dovrebbe essere 0x09473FBCCBC01AF. Posso risolverli con un semplice REPLACE, ma sono sicuro che sia un bug ...
Mark Sinkinson,

0

Come estrarrei il valore di 0x9473FBCCBC01AFE da un piano di query XML come VARBINARY, piuttosto che VARCHAR?

Ho affrontato qualcosa del genere utilizzando HeidiSQL per eseguire query sulle tabelle CASD e risolto con fn_varbintohexstr () , in questo modo:

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

Con HeidiSQL, il valore era errato come '0x3F3F3F3F3F3F3F3F' e divenne corretto come '0x158B1DB75616484695684007CE98E21C'.

OBS: funziona da MSSQL 2008! Spero che sia d'aiuto!


2
Nota le avvertenze sull'uso fn_varbintohexstr() menzionate qui .
Erik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.