sql >> Databasteknik >  >> RDS >> Sqlserver

Lagring av binära datatyper i SQL Server

Introduktion

Dagligt arbete kräver sällan att binära data lagras direkt i databaskolumner. Det är dock mycket användbart i vissa fall.

Tvärtemot vad många tycker kan byte-arrayer hjälpa till med betydligt mer än att bara lagra stora binära objekt (dokument, multimedia, etc.). De kan också användas för att lagra hashvärden och exempeldata för snabbare sökning/analys på hög nivå. Eller så kan de innehålla byte som är i PÅ/AV-läge i något elektroniskt relä. Så fort vi börjar tänka på hårdvarudata som lagras i databaser blir applikationer mer uppenbara.

Till skillnad från VARCHAR-datatyper där du måste ta hand om sortering och teckentabeller, är binära datatyper serier av byte (ibland kallade byte-arrayer i objektorienterade programmeringsspråk), antingen fast (BINAR ) eller variabel (VARBINAR ) i storlek.

För att förstå detaljer om binära typer bättre kommer vi först att göra en kort introduktion till hexadecimala tal, vilket är hur denna data lagras internt.

Hexadecimala tal

Om du hoppade över klassen om hexadecimala tal på gymnasiet, finns en bra introduktion på en särskild Wikipedia-sida. Där kan du bekanta dig med detta numreringsformat.

För att förstå den här artikeln är det viktigt att veta att SQL Server Management Studio visar binära data i hexadecimalt format med prefixet "0x".

Det är ingen stor skillnad mellan hexadecimalt och decimalt numreringsformat. Det hexadecimala formatet använder bas-16-tecken (0-9 och A-F) istället för bas-10 för decimalnotation (0-9). Värdena A-F är siffrorna 10-15 från decimal numreringsnotation.

Det är därför vi använder hexadecimal notation. Eftersom en byte innehåller 8 bitar, vilket tillåter 256 diskreta heltal, är det fördelaktigt att presentera byte i hex-format. Om vi ​​riktar in oss på intervallet 0-256, representeras det som 00-FF i hexadecimal notation. Prefixet i Management studio är för läsningens tydlighet, för att betona att vi visar hexadecimala tal och inte standard decimalvärden.

Manuell värdekonvertering med CAST()

Eftersom binära värden i strikt mening är strängar, kan vi konvertera dem från tal- till teckenformat med CAST eller KONVERTERA SQL-metoder.

Ta en titt på exemplet som använder CAST metod:

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

Använda konverteringsstilar med CONVERT()

CONVERT() metod, till skillnad från CAST() , har ytterligare ett alternativ för att använda konverteringsstilar.

Konverteringsstilar är mallar för regler som används i konverteringsprocessen. CONVERT() används mest i datum/tid operationer. När data är i ett icke-standardformat kan de användas i binär värdekonvertering. Observera att binära datatyper inte stöder automatisk datatypkonvertering utan korrekta parametervärden på plats. Då kommer SQL Server att skapa ett undantag.

Om vi ​​tittar på CONVERT() metoddefinition ser vi att det krävs två obligatoriska och en valfri parameter.

Den första parametern är måldatatypen och den andra är värdet som vi vill konvertera från. Den tredje parametern, i vårt fall, kan värde 1 eller 2 . Värde 1 betyder att CONVERT() bör betrakta inmatningssträngen som en hexadecimal sträng i textformat och värdet 2 betyder att du vill hoppa över 0x prefix.

Ta en titt på exemplen som visar detta beteende:

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

Skillnaden mellan BINARY och VARBINARY

Med binär data kan vi använda två typer av datatyper – fast storlek och variabel storlek. Eller så är de BINÄRA och VARBINÄRA.

Om vi ​​använder variabeln fast storlek utökas innehållet alltid till dess definierade storlek med utfyllnad på 0x00 … – det finns ingen stoppning i variabel längd. Att använda summaoperation på dessa variabler exekveras ingen addition. Värden läggs till varandra. Samma sak är som med strängtyper.

För att demonstrera prefixbeteende kommer vi att använda två enkla exempel med den binära summaoperationen:

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

Varje värde i BINARY(2)-satsen efterfixas med 0x00 värden.

Använda heltalsvärden med binära datatyper

SQL Server kommer med inbyggda metoder för att konvertera mellan numeriska typer och binära typer. Vi visade detta där vi gjorde testet sträng till det binära formatet och sedan tillbaka till BIGINT-formatet, utan att använda funktionen ASCII():

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

Enkel konvertering mellan tecken och hexadecimala värden

För att konvertera mellan charter- och hexadecimala värden är det användbart att skriva en anpassad funktion som skulle utföra denna operation konsekvent. Ett möjligt tillvägagångssätt är nedan:

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

Den här gången använde vi parametervärdet 2 i CONVERT() fungera. Det visar att denna operation inte bör mappas till ASCII-kod och visas utan 0x... prefix.

Exempel på fallstudie:lagring av foton i SQL Server binär typ

Vi brukar närma oss detta problem genom att implementera en anpassad Windows/webbapplikation eller skriva ett anpassat SSIS-paket med C#-kod. I det här exemplet kommer jag bara att använda SQL-språket. Det kan vara mer användbart om du inte har tillgång till databasens front-end-verktyg.

För att lagra bilder i databastabellen måste vi skapa en tabell som kommer att hålla dem. Tabellen måste innehålla kolumner som innehåller bildnamnet och bildens binära innehåll:

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

För att möjliggöra laddning av binära data till SQL Server-instanser måste vi konfigurera servern med två alternativ:

  • Aktivera alternativet OLE Automation Procedures
  • Tilldela BulkAdmin-behörigheten till användaren som utför bildimportprocessen.

Skriptet nedan kommer att utföra uppgiften under den högprivilegierade användaren av 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 börja skriva import- och exportproceduren:

-- 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 använda dessa procedurer från vilken klientapplikation som helst på ett mycket enkelt sätt.

Låt oss föreställa oss att vi har bilder i C:\Pictures\Inp mapp. För att ladda dessa bilder måste vi köra följande kod:

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

På liknande sätt kan vi exportera data till C:\Pictures\Out mapp:

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

Slutsats

Valet mellan binära objekt eller alternativa sätt att lagra binära data i en databas (till exempel att lagra filsökvägar i en databas och hämta dem från disk-/molnlagringen) beror på flera faktorer.

Den allmänna regeln är att om filen är mindre än 256 kilobyte stor bör du lagra den i VARBINARY-kolumnerna. Om binära filer är större än en megabyte bör du lagra dem i filsystemet. Om du har FILESTREAM tillgängligt i SQL Server versioner 2008 och senare, håller det filerna under transaktionskontroll som en logisk del av databasen.

Om du bestämmer dig för att lagra binära filer i SQL Server-tabellen, använd en separat tabell endast för binärt innehåll. Sedan kan du optimera dess lagringsplats och komma åt motorn, förmodligen med hjälp av separata filer och filgrupper för den här tabellen. Den detaljerade informationen finns i den officiella Microsoft-artikeln.

Testa i alla fall båda metoderna och använd den som passar dina behov bäst.


  1. Kopiera sqlite i android studiotillgångar fungerar inte

  2. Vad är skillnaden mellan MyISAM och InnoDB?

  3. Utfasad:mysql_connect()

  4. MySQL tidszoner