Conversion d'un VARCHAR en VARBINARY

17

J'ai gardé un journal des requêtes en cours d'exécution coûteuses, ainsi que leurs plans de requête, dans un tableau pour nous permettre de surveiller les tendances de performances et d'identifier les domaines qui doivent être optimisés.

Cependant, il est arrivé au point où les plans de requête prennent trop de place (car nous stockons le plan entier pour chaque requête).

J'essaie donc de normaliser les données existantes en extrayant QueryPlanHash et QueryPlan vers une autre table.

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

Comme la définition de query_plan_hashin sys.dm_exec_query_statsest un champ binaire (et j'insérerai régulièrement de nouvelles données), j'utilisais VARBINARYle type de données dans ma nouvelle table.

Cependant, l'encart ci-dessous échoue ...

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

.... avec l'erreur

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

Le problème est que les hachages du plan de requête sont déjà au format binaire, cependant stockés en tant que VARCHAR dans le plan de requête XML, par exemple

0x9473FBCCBC01AFE

et CONVERT en BINARY donne une valeur complètement différente

0x3078393437334642434342433031414645

J'ai essayé de changer la définition de valeur dans la sélection XQuery en binaire, mais il n'a renvoyé aucune valeur.

Comment puis-je extraire la valeur de 0x9473FBCCBC01AFEd'un plan de requête XML sous la forme d'un VARBINARYplutôt que d'un VARCHAR?

Mark Sinkinson
la source

Réponses:

28

Vous devez utiliser un style spécifique lorsque vous prévoyez de conserver la même valeur binaire lors de la conversion à partir d'une chaîne. Sinon, SQL Server essaie de coder la chaîne de la même manière qu'il le ferait 'bob'ou 'frank'.

Cela dit, votre chaîne d'entrée ne semble pas correcte - il y a soit un octet manquant, soit un octet de trop. Cela fonctionne bien si je laisse tomber la fin E:

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

Le résultat est binaire:

----------------
0x9473FBCCBC01AF
Aaron Bertrand
la source
1
Ah, ,1c'est ce qui me manquait. C'était plus facile que ce à quoi je m'attendais! Merci!
Mark Sinkinson
Pas sûr de l'octet manquant / supplémentaire. Dans les 2666 enregistrements que j'ai, il y en a 183 qui échouentTRY_CONVERT
Mark Sinkinson
Il peut être nécessaire d'ajouter un caractère (par exemple, 0) à n'importe quelle chaîne avec un nombre de caractères impair. Cela change la valeur, mais devrait toujours changer la même valeur de la même manière (et je ne pense pas que vous aurez des collisions avec ou sans le 0).
Aaron Bertrand
N'est-ce pas un bug? Le queryplanhash dans le xml est explicitement défini sur cette valeur ... Sûrement un TRY_CONVERTà un BINARYne devrait pas revenirNULL
Mark Sinkinson
De la comparaison des valeurs enregistrées dans ma table au xml, c'est en fait un 0 de tête qui manque. La valeur doit donc être 0x09473FBCCBC01AF. Je peux les réparer avec un simple REMPLACEMENT, mais je suis sûr que c'est un bug ...
Mark Sinkinson
0

Comment extraire la valeur de 0x9473FBCCBC01AFE d'un plan de requête XML en tant que VARBINARY, plutôt que VARCHAR?

J'ai fait face à quelque chose comme ça en utilisant HeidiSQL pour interroger les tables CASD, et j'ai résolu avec fn_varbintohexstr () , comme ceci:

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

Avec HeidiSQL, la valeur était incorrecte comme '0x3F3F3F3F3F3F3F3F' et est devenue correcte comme '0x158B1DB75616484695684007CE98E21C'.

OBS: Fonctionne depuis MSSQL 2008! J'espère que cela aide!

MMJ
la source
2
Notez les mises en garde concernant l'utilisation fn_varbintohexstr() mentionnées ici .
Erik