Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Archiviazione di tipi di dati binari in SQL Server

Introduzione

Il lavoro quotidiano richiede raramente l'archiviazione di dati binari direttamente nelle colonne del database. Tuttavia, in alcuni casi è molto utile.

Contrariamente all'opinione popolare, gli array di byte possono aiutare molto di più della semplice memorizzazione di oggetti binari di grandi dimensioni (documenti, file multimediali, ecc.). Inoltre, possono essere utilizzati per memorizzare valori hash e dati di esempio per una ricerca più rapida/analisi di alto livello. Oppure potrebbero contenere byte che sono in stato ON/OFF in alcuni relè elettronici. Non appena iniziamo a pensare ai dati hardware archiviati nei database, le applicazioni diventano più evidenti.

A differenza dei tipi di dati VARCHAR in cui è necessario occuparsi delle regole di confronto e delle tabelle codici, i tipi di dati binari sono serie di byte (a volte chiamati array di byte nei linguaggi di programmazione orientati agli oggetti), di dimensioni fisse (BINAR ) o variabili (VARBINAR ).

Per comprendere meglio i dettagli sui tipi binari, faremo prima una breve introduzione ai numeri esadecimali, che sono il modo in cui questi dati vengono archiviati internamente.

Numeri esadecimali

Se al liceo hai saltato la lezione sui numeri esadecimali, puoi trovare una buona introduzione su una pagina Wikipedia dedicata. Lì puoi familiarizzare con questo formato di numerazione.

Per comprendere questo articolo, è importante sapere che SQL Server Management Studio visualizza i dati binari in formato esadecimale con il prefisso "0x".

Non c'è una grande differenza tra il formato di numerazione esadecimale e decimale. Il formato esadecimale utilizza i segni in base 16 (0-9 e A-F) invece della notazione decimale in base 10 (0-9). I valori A-F sono i numeri 10-15 dalla notazione di numerazione decimale.

Questo è il motivo per cui usiamo la notazione esadecimale. Poiché un byte contiene 8 bit, consentendo 256 numeri interi discreti, è vantaggioso presentare i byte in formato esadecimale. Se puntiamo all'intervallo 0-256, viene rappresentato come 00-FF in notazione esadecimale. Il prefisso in Management Studio serve per chiarezza di lettura, per sottolineare che stiamo mostrando numeri esadecimali e non il predefinito valori decimali.

Conversione manuale del valore mediante CAST()

Poiché i valori binari sono, in senso stretto, stringhe, possiamo convertirli dal formato numerico al formato carattere usando CAST o CONVERTI Metodi SQL.

Dai un'occhiata all'esempio che utilizza il CAST metodo:

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

Utilizzo degli stili di conversione con CONVERT()

CONVERTI() metodo, a differenza di CAST() , ha un'opzione aggiuntiva per utilizzare gli stili di conversione.

Gli stili di conversione sono modelli per le regole utilizzate nel processo di conversione. CONVERTI() viene utilizzato principalmente nelle operazioni di data/ora. Quando i dati sono in un formato non standard, possono essere utilizzati nella conversione di valori binari. Si noti che i tipi di dati binari non supportano la conversione automatica del tipo di dati senza i valori dei parametri appropriati. Quindi SQL Server genererà un'eccezione.

Se osserviamo il CONVERT() definizione del metodo, vediamo che richiede due parametri obbligatori e uno opzionale.

Il primo parametro è il tipo di dati di destinazione e il secondo è il valore da cui vorremmo convertire. Il terzo parametro, nel nostro caso, può valutare 1 o 2 . Valore 1 significa che CONVERT() dovrebbe considerare la stringa di input come una stringa esadecimale in formato testo e il valore 2 significa che vuoi saltare 0x prefisso.

Dai un'occhiata agli esempi che mostrano questo comportamento:

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);  

Differenza tra BINARY e VARBINARY

Con i dati binari, possiamo utilizzare due tipi di tipi di dati:dimensione fissa e dimensione variabile. Oppure sono BINARY e VARBINARY.

Se utilizziamo la variabile a dimensione fissa, il contenuto viene sempre esteso alla dimensione definita con un riempimento di 0x00 … – non ci sono imbottiture a lunghezza variabile. L'uso dell'operazione di somma su queste variabili non viene eseguita alcuna addizione. I valori vengono aggiunti l'uno all'altro. Lo stesso vale per i tipi di stringa.

Per dimostrare il comportamento del prefisso useremo due semplici esempi con l'operazione di somma 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)); 

Ogni valore nell'istruzione BINARY(2) è postfisso con 0x00 valori.

Utilizzo di valori interi con tipi di dati binari

SQL Server viene fornito con metodi integrati per la conversione tra tipi numerici e tipi binari. Lo abbiamo dimostrato quando abbiamo girato il Test stringa nel formato binario, quindi di nuovo nel formato BIGINT, senza utilizzare la funzione ASCII():

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

Semplice conversione tra caratteri e valori esadecimali

Per convertire tra valori charter ed esadecimali, è utile scrivere una funzione personalizzata che esegua questa operazione in modo coerente. Un possibile approccio è il seguente:

-- 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') 

Questa volta abbiamo utilizzato il valore del parametro 2 in CONVERT() funzione. Mostra che questa operazione non deve essere mappata su codice ASCII ed essere visualizzata senza 0x... prefisso.

Case study di esempio:archiviazione di foto nel tipo binario di SQL Server

Di solito affrontiamo questo problema implementando un'applicazione Windows/Web personalizzata o scrivendo un pacchetto SSIS personalizzato con codice C#. In questo esempio userò solo il linguaggio SQL. Può essere più utile se non hai accesso agli strumenti front-end del database.

Per memorizzare le immagini nella tabella del database, dobbiamo creare una tabella che le contenga. La tabella deve includere colonne contenenti il ​​nome dell'immagine e il contenuto binario dell'immagine:

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

Per abilitare il caricamento di dati binari nell'istanza di SQL Server, è necessario configurare il server con due opzioni:

  • Abilita l'opzione Procedure di automazione OLE
  • Assegnare il privilegio BulkAdmin all'utente che esegue il processo di importazione dell'immagine.

Lo script seguente eseguirà l'attività sotto l'utente con privilegi elevati dell'istanza di 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 

Ora possiamo iniziare a scrivere la procedura di importazione ed esportazione:

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

Ora possiamo utilizzare queste procedure da qualsiasi applicazione client in un modo molto semplice.

Immaginiamo di avere immagini in C:\Pictures\Inp cartella. Per caricare queste immagini, dobbiamo eseguire il seguente codice:

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

Allo stesso modo possiamo esportare i dati in C:\Pictures\Out cartella:

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

Conclusione

La scelta tra oggetti binari o mezzi alternativi per archiviare dati binari in un database (ad esempio, archiviare percorsi di file in un database e recuperarli dall'archivio su disco/cloud) dipende da molteplici fattori.

La regola generale è che se il file ha una dimensione inferiore a 256 kilobyte, è necessario memorizzarlo nelle colonne VARBINARY. Se i file binari sono più grandi di un megabyte, dovresti archiviarli nel file system. Se hai FILESTREAM disponibile in SQL Server versioni 2008 e successive, mantiene i file sotto il controllo transazionale come parte logica del database.

Se si decide di archiviare i file binari nella tabella di SQL Server, utilizzare una tabella separata solo per il contenuto binario. Quindi puoi ottimizzare la sua posizione di archiviazione e accedere al motore, probabilmente utilizzando File e FileGroup separati per questa tabella. Le informazioni dettagliate sono disponibili nell'articolo ufficiale di Microsoft.

In ogni caso, prova entrambi gli approcci e usa quello più adatto alle tue esigenze.