Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Speichern von binären Datentypen in SQL Server

Einführung

Bei der täglichen Arbeit müssen Binärdaten nur selten direkt in Datenbankspalten gespeichert werden. In einigen Fällen ist es jedoch sehr nützlich.

Entgegen der landläufigen Meinung können Byte-Arrays bei wesentlich mehr helfen, als nur große binäre Objekte (Dokumente, Multimedia usw.) zu speichern. Sie können auch verwendet werden, um Hash-Werte und Beispieldaten für eine schnellere Suche/High-Level-Analyse zu speichern. Oder sie können Bytes enthalten, die sich in einem elektronischen Relais im EIN/AUS-Zustand befinden. Sobald wir anfangen, über in Datenbanken gespeicherte Hardwaredaten nachzudenken, werden Anwendungen offensichtlicher.

Im Gegensatz zu VARCHAR-Datentypen, bei denen Sie sich um Sortierung und Codepages kümmern müssen, sind binäre Datentypen Reihen von Bytes (in objektorientierten Programmiersprachen manchmal als Byte-Arrays bezeichnet), die entweder eine feste (BINAR) oder eine variable (VARBINAR) Größe haben.

Um Details zu Binärtypen besser zu verstehen, werden wir zunächst eine kurze Einführung in Hexadezimalzahlen geben, wie diese Daten intern gespeichert werden.

Hexadezimalzahlen

Wenn Sie in der High School den Kurs über Hexadezimalzahlen übersprungen haben, finden Sie eine gute Einführung auf einer speziellen Wikipedia-Seite. Dort können Sie sich mit diesem Nummerierungsformat vertraut machen.

Zum Verständnis dieses Artikels ist es wichtig zu wissen, dass SQL Server Management Studio Binärdaten im Hexadezimalformat mit dem Präfix „0x“ anzeigt.

Es gibt keinen großen Unterschied zwischen dem hexadezimalen und dem dezimalen Nummerierungsformat. Das Hexadezimalformat verwendet Zeichen zur Basis 16 (0-9 und A-F) anstelle der Basis 10 der Dezimalschreibweise (0-9). Die Werte A-F sind die Zahlen 10-15 aus der Dezimalschreibweise.

Aus diesem Grund verwenden wir die hexadezimale Schreibweise. Da ein Byte 8 Bits enthält, was 256 diskrete ganze Zahlen ermöglicht, ist es vorteilhaft, Bytes im Hex-Format darzustellen. Wenn wir auf den Bereich 0-256 abzielen, wird er als 00-FF in hexadezimaler Notation dargestellt. Das Präfix in Management Studio dient der besseren Lesbarkeit, um zu betonen, dass wir Hexadezimalzahlen und nicht den Standard anzeigen Dezimalwerte.

Manuelle Wertkonvertierung mit CAST()

Da Binärwerte streng genommen Strings sind, können wir sie mit CAST vom Zahlen- in das Zeichenformat umwandeln oder KONVERTIEREN SQL-Methoden.

Sehen Sie sich das Beispiel an, das CAST verwendet Methode:

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

Umwandlungsstile mit CONVERT() verwenden

CONVERT() -Methode, im Gegensatz zu CAST() , hat eine zusätzliche Option zur Verwendung von Konvertierungsstilen.

Konvertierungsstile sind Vorlagen für Regeln, die im Konvertierungsprozess verwendet werden. CONVERT() wird hauptsächlich in Datums-/Uhrzeitoperationen verwendet. Wenn die Daten in einem nicht standardmäßigen Format vorliegen, können sie bei der Umwandlung von Binärwerten verwendet werden. Beachten Sie, dass binäre Datentypen keine automatische Datentypkonvertierung unterstützen, wenn keine geeigneten Parameterwerte vorhanden sind. Dann löst SQL Server eine Ausnahme aus.

Betrachten wir die CONVERT() Methodendefinition sehen wir, dass es zwei obligatorische und einen optionalen Parameter braucht.

Der erste Parameter ist der Zieldatentyp und der zweite der Wert, von dem wir konvertieren möchten. Der dritte Parameter kann in unserem Fall den Wert 1 haben oder 2 . Wert 1 bedeutet, dass CONVERT() sollte die Eingabezeichenfolge als hexadezimale Zeichenfolge im Textformat betrachten und den Wert 2 haben bedeutet, dass Sie das 0x überspringen möchten Präfix.

Sehen Sie sich die Beispiele an, die dieses Verhalten zeigen:

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

Unterschied zwischen BINARY und VARBINARY

Bei binären Daten können wir zwei Arten von Datentypen verwenden – feste Größe und variable Größe. Oder sie sind BINARY und VARBINARY.

Wenn wir die Variable mit fester Größe verwenden, wird der Inhalt immer auf seine definierte Größe mit Auffüllung von 0x00 erweitert … – es gibt keine Polsterung in variabler Länge. Bei Verwendung der Summenoperation an diesen Variablen wird keine Addition ausgeführt. Werte werden aneinander angehängt. Dasselbe ist wie bei String-Typen.

Um das Präfixverhalten zu demonstrieren, verwenden wir zwei einfache Beispiele mit der binären Summenoperation:

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

Jedem Wert in der BINARY(2)-Anweisung ist 0x00 nachgestellt Werte.

Integerwerte mit binären Datentypen verwenden

SQL Server verfügt über integrierte Methoden zum Konvertieren zwischen numerischen Typen und binären Typen. Wir haben dies demonstriert, wo wir den Test gedreht haben string in das Binärformat und dann zurück in das BIGINT-Format, ohne die ASCII()-Funktion zu verwenden:

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

Einfache Konvertierung zwischen Zeichen- und Hexadezimalwerten

Um zwischen Charter- und Hexadezimalwerten umzuwandeln, ist es hilfreich, eine benutzerdefinierte Funktion zu schreiben, die diese Operation konsistent ausführt. Ein möglicher Ansatz ist unten:

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

Dieses Mal haben wir den Parameterwert 2 verwendet im CONVERT() Funktion. Es zeigt, dass diese Operation nicht auf ASCII-Code abgebildet und ohne 0x… angezeigt werden sollte Präfix.

Beispielfallstudie:Speichern von Fotos im SQL Server-Binärtyp

Normalerweise gehen wir dieses Problem an, indem wir eine benutzerdefinierte Windows-/Webanwendung implementieren oder ein benutzerdefiniertes SSIS-Paket mit C#-Code schreiben. In diesem Beispiel verwende ich nur die SQL-Sprache. Es kann nützlicher sein, wenn Sie keinen Zugriff auf die Datenbank-Front-End-Tools haben.

Um Bilder in der Datenbanktabelle zu speichern, müssen wir eine Tabelle erstellen, die sie enthält. Die Tabelle muss Spalten enthalten, die den Bildnamen und den Binärinhalt des Bildes enthalten:

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

Um das Laden von Binärdaten in die SQL Server-Instanz zu ermöglichen, müssen wir den Server mit zwei Optionen konfigurieren:

  • Aktivieren Sie die Option OLE-Automatisierungsverfahren
  • Zuweisung der BulkAdmin-Berechtigung an den Benutzer, der den Bildimportprozess ausführt.

Das folgende Skript führt die Aufgabe unter dem hochprivilegierten Benutzer der SQL Server-Instanz aus:

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 

Jetzt können wir damit beginnen, die Import- und Exportprozedur zu schreiben:

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

Jetzt können wir diese Prozeduren auf sehr einfache Weise von jeder Client-Anwendung aus verwenden.

Stellen wir uns vor, wir haben Bilder in C:\Pictures\Inp Mappe. Um diese Bilder zu laden, müssen wir den folgenden Code ausführen:

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

Auf ähnliche Weise können wir Daten nach C:\Pictures\Out exportieren Ordner:

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

Schlussfolgerung

Die Wahl zwischen binären Objekten oder alternativen Methoden zum Speichern binärer Daten in einer Datenbank (z. B. Speichern von Dateipfaden in einer Datenbank und Abrufen aus dem Festplatten-/Cloud-Speicher) hängt von mehreren Faktoren ab.

Die allgemeine Regel lautet:Wenn die Datei weniger als 256 Kilobyte groß ist, sollten Sie sie in den VARBINARY-Spalten speichern. Wenn Binärdateien größer als ein Megabyte sind, sollten Sie sie im Dateisystem speichern. Wenn Sie FILESTREAM in den SQL Server-Versionen 2008 und höher verfügbar haben, werden die Dateien als logischer Teil der Datenbank unter Transaktionskontrolle gehalten.

Wenn Sie Binärdateien in der SQL Server-Tabelle speichern möchten, verwenden Sie eine separate Tabelle nur für Binärinhalte. Dann können Sie den Speicherort optimieren und auf die Engine zugreifen, indem Sie wahrscheinlich separate Dateien und Dateigruppen für diese Tabelle verwenden. Die detaillierten Informationen finden Sie im offiziellen Microsoft-Artikel.

Testen Sie in jedem Fall beide Ansätze und verwenden Sie den, der Ihren Anforderungen am besten entspricht.