Convertir un VARCHAR a VARBINARY


17

He mantenido un registro de consultas costosas en ejecución, junto con sus planes de consulta, en una tabla que nos permite monitorear las tendencias en el rendimiento e identificar áreas que necesitan optimización.

Sin embargo, ha llegado al punto en que los planes de consulta ocupan demasiado espacio (ya que estamos almacenando el plan completo en cada consulta).

Por lo tanto, intento normalizar los datos existentes extrayendo QueryPlanHash y QueryPlan a otra tabla.

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

Como la definición de query_plan_hashin sys.dm_exec_query_statses un campo binario (y regularmente insertaré nuevos datos), estaba usando VARBINARYel tipo de datos en mi nueva tabla.

Sin embargo, el siguiente inserto falla ...

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 el error

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

El problema es que los hashes del plan de consulta ya están en formato binario, pero se almacenan como VARCHAR en el Plan de consulta XML, por ejemplo

0x9473FBCCBC01AFE

y CONVERT a BINARY da un valor completamente diferente

0x3078393437334642434342433031414645

Intenté cambiar la definición del valor en XQuery select a binario, pero luego no devolvió valores.

¿Cómo extraería el valor de 0x9473FBCCBC01AFEun plan de consulta XML como a VARBINARY, en lugar de a VARCHAR?

Respuestas:


28

Debe usar un estilo específico cuando espera mantener el mismo valor binario al convertir desde una cadena. De lo contrario, SQL Server intenta codificar la cadena de la misma manera que codificaría 'bob'o 'frank'.

Dicho esto, su cadena de entrada no se ve correcta: falta un byte o un byte demasiado. Esto funciona bien si dejo caer el final E:

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

El resultado es binario:

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

1
Ah, ,1eso era lo que me faltaba. ¡Eso fue más fácil de lo que esperaba! ¡Gracias!
Mark Sinkinson el

No estoy seguro sobre el byte perdido / extra. En los 2666 registros que tengo, hay 183 que fallanTRY_CONVERT
Mark Sinkinson

Es posible que deba agregar un carácter (digamos, 0) a cualquier cadena con un recuento de caracteres impar. Eso cambia el valor, pero siempre debe cambiar el mismo valor de la misma manera (y no sospecho que tendrá colisiones con o sin el 0).
Aaron Bertrand

¿No es eso un error? El queryplanhash en el xml se establece explícitamente en ese valor ... Seguramente a TRY_CONVERTa a BINARYno debería volverNULL
Mark Sinkinson

Al comparar los valores guardados en mi tabla con el xml, en realidad falta un 0 inicial. Por lo tanto, el valor debe ser 0x09473FBCCBC01AF. Puedo arreglarlos con un simple REEMPLAZO, pero estoy seguro de que es un error ...
Mark Sinkinson

0

¿Cómo extraería el valor de 0x9473FBCCBC01AFE de un plan de consulta XML como un VARBINARIO, en lugar de un VARCHAR?

Me enfrenté a algo así usando HeidiSQL para consultar en tablas CASD, y lo resolví con fn_varbintohexstr () , así:

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

Con HeidiSQL, el valor era incorrecto como '0x3F3F3F3F3F3F3F3F' y se volvió correcto como '0x158B1DB75616484695684007CE98E21C'.

OBS: ¡Funciona desde MSSQL 2008! ¡Espero eso ayude!


2
Tenga en cuenta las advertencias sobre el uso fn_varbintohexstr() mencionadas aquí .
Erik
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.