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

Lagring af binære datatyper i SQL Server

Introduktion

Dagligt arbejde kræver sjældent lagring af binære data direkte til databasekolonner. Det er dog meget nyttigt i nogle tilfælde.

I modsætning til den almindelige opfattelse kan byte-arrays hjælpe med væsentligt mere end blot at opbevare store binære objekter (dokumenter, multimedier osv.). De kan også bruges til at gemme hashværdier og prøvedata for hurtigere søgning/analyse på højt niveau. Eller de kan indeholde bytes, der er i ON/OFF-tilstande i nogle elektroniske relæer. Så snart vi begynder at tænke på hardwaredata, der er gemt i databaser, bliver applikationer mere tydelige.

I modsætning til VARCHAR-datatyper, hvor du skal sørge for sortering og tegntabeller, er binære datatyper serier af bytes (nogle gange kaldet byte-arrays i objektorienterede programmeringssprog), enten faste (BINAR ) eller variable (VARBINAR ) i størrelse.

For bedre at forstå detaljer om binære typer vil vi først lave en kort introduktion til hexadecimale tal, som er hvordan disse data lagres internt.

Hexadecimale tal

Hvis du sprunget over klassen om hexadecimale tal i gymnasiet, kan en god introduktion findes på en dedikeret Wikipedia-side. Der kan du blive fortrolig med dette nummereringsformat.

For at forstå denne artikel er det vigtigt at vide, at SQL Server Management Studio viser binære data i hexadecimalt format med præfikset "0x".

Der er ingen stor forskel mellem hexadecimalt og decimalt nummereringsformat. Det hexadecimale format bruger basis-16-tegn (0-9 og A-F) i stedet for basis-10 i decimalnotation (0-9). Værdierne A-F er tallene 10-15 fra decimalnummereringsnotation.

Det er derfor, vi bruger hexadecimal notation. Da en byte indeholder 8 bits, hvilket giver mulighed for 256 diskrete heltal, er det en fordel at præsentere bytes i hex-format. Hvis vi målretter mod området 0-256, er det repræsenteret som 00-FF i hexadecimal notation. Præfikset i Management Studio er for læseklarheden, for at understrege, at vi viser hexadecimale tal og ikke standard decimalværdier.

Manuel værdikonvertering ved hjælp af CAST()

Da binære værdier i deres strenge forstand er strenge, kan vi konvertere dem fra tal- til tegnformat ved hjælp af CAST eller KONVERT SQL-metoder.

Tag et kig på eksemplet, der bruger CAST metode:

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

Brug af konverteringsstile med CONVERT()

KONVERT() metode, i modsætning til CAST() , har en ekstra mulighed for at bruge konverteringsstile.

Konverteringsstile er skabeloner til regler, der bruges i konverteringsprocessen. KONVERT() bruges mest i dato/klokkeslæt operationer. Når dataene er i et ikke-standardformat, kan de bruges i binær værdikonvertering. Bemærk, at binære datatyper ikke understøtter automatisk datatypekonvertering uden korrekte parameterværdier på plads. Så vil SQL Server give en undtagelse.

Hvis vi ser på CONVERT() metodedefinition, ser vi, at det kræver to obligatoriske og en valgfri parameter.

Den første parameter er måldatatypen, og den anden er den værdi, som vi gerne vil konvertere fra. Den tredje parameter, i vores tilfælde, kan værdien 1 eller 2 . Værdi 1 betyder, at CONVERT() bør betragte inputstrengen som en hexadecimal streng i tekstformat og værdien 2 betyder, at du vil springe 0x over præfiks.

Tag et kig på eksemplerne, der viser denne adfærd:

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

Forskellen mellem BINARY og VARBINARY

Med binære data kan vi bruge to slags datatyper – fast størrelse og variabel størrelse. Eller de er BINÆRE og VARBINÆRE.

Hvis vi bruger variablen med fast størrelse, udvides indholdet altid til dets definerede størrelse med polstring på 0x00 … – der er ingen polstring i variabel længde. Brug af sumoperation på disse variable udføres ingen addition. Værdier føjes til hinanden. Det samme er som med strengtyper.

For at demonstrere præfiksadfærd vil vi bruge to simple eksempler med den binære sum operation:

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

Hver værdi i BINARY(2)-sætningen efterfikses med 0x00 værdier.

Brug af heltalsværdier med binære datatyper

SQL Server kommer med indbyggede metoder til at konvertere mellem numeriske typer og binære typer. Vi demonstrerede dette, hvor vi gjorde testen streng ind i det binære format og derefter tilbage til BIGINT-formatet uden at bruge ASCII()-funktionen:

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

Simpel konvertering mellem tegn og hexadecimale værdier

For at konvertere mellem charter- og hexadecimale værdier er det nyttigt at skrive en brugerdefineret funktion, der ville udføre denne operation konsekvent. En mulig tilgang er nedenfor:

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

Denne gang brugte vi parameterværdien 2 i CONVERT() fungere. Det viser, at denne operation ikke skal tilknyttes ASCII-kode og vises uden 0x... præfiks.

Eksempel på casestudie:Lagring af billeder i SQL Server Binær Type

Vi nærmer os normalt dette problem ved at implementere en brugerdefineret windows/webapplikation eller skrive en tilpasset SSIS-pakke med C#-kode. I dette eksempel vil jeg kun bruge SQL-sproget. Det kan være mere nyttigt, hvis du ikke har adgang til databasens frontend-værktøjer.

For at gemme billeder i databasetabellen skal vi oprette en tabel, der kan indeholde dem. Tabellen skal indeholde kolonner med billednavnet og billedets binære indhold:

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

For at aktivere indlæsning af binære data til SQL Server-instans, skal vi konfigurere serveren med to muligheder:

  • Aktiver indstillingen OLE Automation Procedures
  • Tildeling af BulkAdmin-privilegiet til brugeren, der udfører billedimportprocessen.

Scriptet nedenfor vil udføre opgaven under den højtprivilegerede bruger af SQL Server-instansen:

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 

Nu kan vi begynde at skrive import- og eksportproceduren:

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

Nu kan vi bruge disse procedurer fra enhver klientapplikation på en meget enkel måde.

Lad os forestille os, at vi har billeder i C:\Pictures\Inp folder. For at indlæse disse billeder skal vi udføre følgende kode:

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

På lignende måde kan vi eksportere data til C:\Pictures\Out mappe:

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

Konklusion

Valget mellem binære objekter eller alternative måder at lagre binære data på i en database (f.eks. lagring af filstier i en database og hentning af dem fra disk-/skylageret) afhænger af flere faktorer.

Den generelle regel er, at hvis filen er mindre end 256 kilobyte i størrelse, skal du gemme den i VARBINARY-kolonnerne. Hvis binære filer er større end en megabyte, bør du gemme dem på filsystemet. Hvis du har FILESTREAM tilgængelig i SQL Server-versioner 2008 og nyere, holder det filerne under transaktionskontrol som en logisk del af databasen.

Hvis du beslutter dig for at gemme binære filer i SQL Server-tabellen, skal du kun bruge en separat tabel til binært indhold. Så kan du optimere dens lagerplacering og få adgang til motoren, sandsynligvis ved at bruge separate filer og filgrupper til denne tabel. De detaljerede oplysninger er tilgængelige i den officielle Microsoft-artikel.

Under alle omstændigheder, test begge tilgange og brug den, der passer bedst til dine behov.


  1. Spotlight Cloud Basic:Bedste gratis værktøj til overvågning af databaseydeevne

  2. Find det samlede antal resultater i mySQL-forespørgsel med offset+limit

  3. syntaksfejl med opdateringsforespørgsel, når du slutter dig til en tabel

  4. Tjek om der findes en række, ellers indsæt