sql >> Base de Datos >  >> RDS >> Sqlserver

Almacenamiento de tipos de datos binarios en SQL Server

Introducción

El trabajo diario rara vez requiere almacenar datos binarios directamente en las columnas de la base de datos. Sin embargo, es muy útil en algunos casos.

Contrariamente a la opinión popular, las matrices de bytes pueden ayudar mucho más que simplemente almacenar objetos binarios grandes (documentos, multimedia, etc.). Además, se pueden usar para almacenar valores hash y datos de muestra para una búsqueda más rápida/análisis de alto nivel. O bien, pueden contener bytes que están en estado ON/OFF en algún relé electrónico. Tan pronto como comenzamos a pensar en los datos de hardware almacenados en bases de datos, las aplicaciones se vuelven más evidentes.

A diferencia de los tipos de datos VARCHAR en los que debe encargarse de la intercalación y las páginas de códigos, los tipos de datos binarios son series de bytes (a veces llamados conjuntos de bytes en lenguajes de programación orientados a objetos), de tamaño fijo (BINAR) o variable (VARBINAR).

Para comprender mejor los detalles sobre los tipos binarios, primero haremos una breve introducción a los números hexadecimales, que es cómo se almacenan internamente estos datos.

Números hexadecimales

Si te saltaste la clase de números hexadecimales en la escuela secundaria, puedes encontrar una buena introducción en una página dedicada de Wikipedia. Allí podrá familiarizarse con este formato de numeración.

Para comprender este artículo, es importante saber que SQL Server Management Studio muestra datos binarios en formato hexadecimal con el prefijo "0x".

No hay gran diferencia entre el formato de numeración hexadecimal y decimal. El formato hexadecimal utiliza signos de base 16 (0-9 y A-F) en lugar de la base 10 de la notación decimal (0-9). Los valores A-F son números 10-15 de la notación de numeración decimal.

Es por eso que usamos la notación hexadecimal. Dado que un byte contiene 8 bits, lo que permite 256 números enteros discretos, es conveniente presentar los bytes en formato hexadecimal. Si apuntamos al rango 0-256, se representa como 00-FF en notación hexadecimal. El prefijo en Management Studio es para la claridad de lectura, para enfatizar que estamos mostrando números hexadecimales y no el predeterminado valores decimales.

Conversión manual de valores mediante CAST()

Dado que los valores binarios son, en sentido estricto, cadenas, podemos convertirlos de formato de número a carácter usando CAST o CONVERTIR Métodos SQL.

Eche un vistazo al ejemplo que usa el CAST método:

SELECT CAST('HexTest' AS VARBINARY);                 
SELECT CAST(0x48657854657374 AS VARCHAR);  

Uso de estilos de conversión con CONVERT()

CONVERTIR() método, a diferencia de CAST() , tiene una opción adicional para usar estilos de conversión.

Los estilos de conversión son plantillas para las reglas utilizadas en el proceso de conversión. CONVERTIR() se utiliza principalmente en operaciones de fecha/hora. Cuando los datos están en un formato no estándar, se pueden usar en la conversión de valores binarios. Tenga en cuenta que los tipos de datos binarios no admiten la conversión automática de tipos de datos sin los valores de parámetros adecuados. Entonces SQL Server lanzará una excepción.

Si miramos el CONVERT() definición del método, vemos que toma dos parámetros obligatorios y uno opcional.

El primer parámetro es el tipo de datos de destino y el segundo es el valor desde el que nos gustaría convertir. El tercer parámetro, en nuestro caso, puede valer 1 o 2 . Valor 1 significa que CONVERTIR() debe considerar la cadena de entrada como una cadena hexadecimal en formato de texto y el valor 2 significa que desea omitir el 0x prefijo.

Echa un vistazo a los ejemplos que muestran ese comportamiento:

DECLARE @MyString NVARCHAR(500)='0x48657854657374';

SELECT CONVERT(VARBINARY(MAX), @MyString );    
-- String value is directly converted to binary value - we wanted is to change the datatype 
-- and not convert "0x.." prefix to the hexadecimal value

SELECT CONVERT(VARBINARY(MAX), @MyString, 1);  

Diferencia entre BINARIO y VARBINARIO

Con datos binarios, podemos usar dos tipos de tipos de datos:tamaño fijo y tamaño variable. O bien, son BINARIO y VARBINARIO.

Si usamos la variable de tamaño fijo, el contenido siempre se extiende a su tamaño definido con un relleno de 0x00 … – no hay relleno en longitud variable. El uso de la operación de suma en estas variables no es una suma ejecutada. Los valores se añaden unos a otros. Lo mismo ocurre con los tipos de cadena.

Para demostrar el comportamiento del prefijo, usaremos dos ejemplos simples con la operación de suma binaria:

SELECT CAST('T' AS BINARY(1)) + CAST('e' AS BINARY(1)) + CAST('s' AS BINARY(1)) + CAST('t' AS BINARY(1)); 
SELECT CAST('T' AS BINARY(2)) + CAST('e' AS BINARY(2)) + CAST('s' AS BINARY(2)) + CAST('t' AS BINARY(2)); 

Cada valor en la instrucción BINARY(2) tiene el sufijo 0x00 valores.

Uso de valores enteros con tipos de datos binarios

SQL Server viene con métodos incorporados para convertir entre tipos numéricos y tipos binarios. Demostramos esto cuando convertimos la Prueba cadena en el formato binario, y luego de vuelta al formato BIGINT, sin usar la función ASCII():

SELECT CAST('Test' AS VARBINARY(MAX));
SELECT CAST(CAST('Test' AS VARBINARY(MAX)) AS BIGINT);

Conversión simple entre caracteres y valores hexadecimales

Para convertir entre valores charter y hexadecimales, es útil escribir una función personalizada que realice esta operación de manera consistente. Un posible enfoque es el siguiente:

-- DROP FUNCTION dbo.FN_CH_HEX(@InputValue CHAR(1)

CREATE OR ALTER FUNCTION dbo.FN_CH_HEX(@InputValue CHAR(1))
RETURNS CHAR(2)
AS
BEGIN
    RETURN(CONVERT(CHAR(2), CAST(@InputValue AS BINARY(1)), 2));
END;

-- SELECT dbo.FN_CH_HEX('A') 

Esta vez usamos el valor del parámetro 2 en CONVERTIR() función. Muestra que esta operación no debe asignarse al código ASCII y mostrarse sin el 0x… prefijo.

Ejemplo de estudio de caso:almacenamiento de fotos en tipo binario de SQL Server

Por lo general, abordamos este problema implementando una aplicación web/Windows personalizada o escribiendo un paquete SSIS personalizado con código C#. En este ejemplo, usaré solo el lenguaje SQL. Puede ser más útil si no tiene acceso a las herramientas de front-end de la base de datos.

Para almacenar imágenes en la tabla de la base de datos, necesitamos crear una tabla que las contenga. La tabla debe incluir columnas que contengan el nombre de la imagen y el contenido binario de la imagen:

-- DROP TABLE T_BINARY_DATA 

CREATE TABLE T_BINARY_DATA 
(
   PICTURE_ID INT IDENTITY(1,1) PRIMARY KEY,
   PICTURE_NAME NVARCHAR(100),
   PICTURE_FILE_NAME NVARCHAR(500),
   PICTURE_DATA VARBINARY(MAX)
)
GO

Para habilitar la carga de datos binarios en la instancia de SQL Server, debemos configurar el servidor con dos opciones:

  • Habilite la opción Procedimientos de automatización OLE
  • Asignación del privilegio BulkAdmin al usuario que ejecuta el proceso de importación de imágenes.

El siguiente script realizará la tarea bajo el usuario con privilegios elevados de la instancia de SQL Server:

USE MASTER
GO
EXEC sp_configure 'show advanced options', 1; 
GO
RECONFIGURE; 
GO
EXEC sp_configure 'Ole Automation Procedures', 1; 
GO
RECONFIGURE; 
GO
-- Add 'bulkadmin' to the correct user
ALTER SERVER ROLE [bulkadmin] ADD MEMBER [NT AUTHORITY\SYSTEM] 
GO 

Ahora podemos comenzar a escribir el procedimiento de importación y exportación:

-- DROP PROCEDURE dbo.proc_ImportBinary 
-- DROP PROCEDURE dbo.proc_ExportBinary 

CREATE PROCEDURE dbo.proc_ImportBinary 
(
     @PICTURE_NAME      NVARCHAR(100)
   , @FOLDER_PATH       NVARCHAR(500)
   , @PICTURE_FILE_NAME NVARCHAR(500)
   )
AS
BEGIN
   DECLARE @OutputPath NVARCHAR(4000);
   DECLARE @TSQLDYN    NVARCHAR(4000);
   
   SET @OutputPath = CONCAT(@OutputPath,'\',@PICTURE_FILE_NAME)
   SET @TSQLDYN = 'INSERT INTO T_BINARY_DATA(PICTURE_NAME,PICTURE_FILE_NAME,PICTURE_DATA) '
                + 'SELECT ' + '''' + @PICTURE_NAME + '''' + ',' + '''' + @PICTURE_FILE_NAME + '''' + ', * ' 
				+ '  FROM Openrowset( Bulk ' + '''' + @OutputPath + '''' + ', Single_Blob) as img'

   EXEC (@TSQLDYN)   
END
GO


CREATE PROCEDURE dbo.proc_ExportBinary (
     @PICTURE_NAME      NVARCHAR(100)
   , @FOLDER_PATH       NVARCHAR(500)
   , @PICTURE_FILE_NAME NVARCHAR(500)
   )
AS
BEGIN
   DECLARE @Binary     VARBINARY (max);
   DECLARE @OutputPath NVARCHAR(4000);
   DECLARE @Obj        INT
 
   SELECT @Binary = (
         SELECT CONVERT(VARBINARY(max), PICTURE_DATA , 1)
           FROM T_BINARY_DATA 
          WHERE PICTURE_NAME  = @PICTURE_NAME
         );
 
   SET @OutputPath = CONCAT(@FOLDER_PATH, '\', @PICTURE_FILE_NAME);
         
    BEGIN TRY
     EXEC sp_OACreate 'ADODB.Stream', @Obj OUTPUT;
     EXEC sp_OASetProperty @Obj ,'Type',1;
     EXEC sp_OAMethod @Obj,'Open';
     EXEC sp_OAMethod @Obj,'Write', NULL, @Binary;
     EXEC sp_OAMethod @Obj,'SaveToFile', NULL, @OutputPath, 2;
     EXEC sp_OAMethod @Obj,'Close';
     EXEC sp_OADestroy @Obj;
    END TRY
    
 BEGIN CATCH
  EXEC sp_OADestroy @Obj;
 END CATCH
 
   SET NOCOUNT OFF
END
GO

Ahora podemos utilizar estos procedimientos desde cualquier aplicación cliente de una forma muy sencilla.

Imaginemos que tenemos imágenes en el C:\Pictures\Inp carpeta. Para cargar estas imágenes, necesitamos ejecutar el siguiente código:

-- Load picture to table row
exec dbo.proc_ImportBinary ‘MyPic’, ‘C:\Pictures\Inp’, ‘MyPic.jpg’ 

De manera similar, podemos exportar datos a C:\Pictures\Out carpeta:

exec dbo.proc_ExportBinary ‘MyPic’, ‘C:\Pictures\Out’, ‘MyPic.jpg’

Conclusión

La elección entre objetos binarios o medios alternativos para almacenar datos binarios en una base de datos (por ejemplo, almacenar rutas de archivos en una base de datos y recuperarlos del disco/almacenamiento en la nube) depende de múltiples factores.

La regla general es que si el archivo tiene un tamaño inferior a 256 kilobytes, debe almacenarlo en las columnas VARBINARY. Si los archivos binarios tienen más de un megabyte, debe almacenarlos en el sistema de archivos. Si tiene FILESTREAM disponible en las versiones de SQL Server 2008 y posteriores, mantiene los archivos bajo control transaccional como una parte lógica de la base de datos.

Si decide almacenar archivos binarios en la tabla de SQL Server, use una tabla separada solo para el contenido binario. Luego puede optimizar su ubicación de almacenamiento y acceder al motor, probablemente usando archivos y grupos de archivos separados para esta tabla. La información detallada está disponible en el artículo oficial de Microsoft.

En cualquier caso, pruebe ambos enfoques y utilice el que mejor se adapte a sus necesidades.