Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Съхранение на двоични типове данни в SQL Server

Въведение

Ежедневната работа рядко изисква съхраняване на двоични данни директно в колоните на базата данни. В някои случаи обаче е много полезно.

Противно на общоприетото мнение, байтовите масиви могат да помогнат със значително повече от просто съхраняване на големи двоични обекти (документи, мултимедия и т.н.). Също така, те могат да се използват за съхраняване на хеш стойности и примерни данни за по-бързо търсене/анализ на високо ниво. Или те могат да съдържат байтове, които са в състояние ON/OFF в някакво електронно реле. Веднага щом започнем да мислим за хардуерни данни, съхранявани в бази данни, приложенията стават по-очевидни.

За разлика от типовете данни VARCHAR, при които трябва да се грижите за съпоставянето и кодовите страници, двоичните типове данни са серии от байтове (понякога наричани байтови масиви в обектно-ориентирани езици за програмиране), или с фиксиран (BINAR), или променлив (VARBINAR) размер.

За да разберем по-добре подробностите за двоичните типове, първо ще направим кратко въведение в шестнадесетичните числа, които са начинът, по който тези данни се съхраняват вътрешно.

Шестнадесетични числа

Ако сте пропуснали часа по шестнадесетични числа в гимназията, добро въведение може да се намери на специална страница в Уикипедия. Там можете да се запознаете с този формат на номериране.

За да разберете тази статия, е важно да знаете, че SQL Server Management Studio показва двоични данни в шестнадесетичен формат с префикс „0x“.

Няма голяма разлика между шестнадесетичния и десетичния формат на номериране. Шестнадесетичният формат използва знаци с основа 16 (0-9 и A-F) вместо основата-10 на десетичната нотация (0-9). Стойностите A-F са числа 10-15 от десетичната номерация.

Ето защо използваме шестнадесетична нотация. Тъй като един байт съдържа 8 бита, позволяващи 256 дискретни цели числа, е изгодно да се представят байтовете в шестнадесетичен формат. Ако се насочваме към диапазон 0-256, той се представя като 00-FF в шестнадесетична нотация. Префиксът в Management Studio е за яснота на четенето, за да подчертае, че показваме шестнадесетични числа, а не по подразбиране десетични стойности.

Ръчно преобразуване на стойност с помощта на CAST()

Тъй като двоичните стойности в тесния си смисъл са низове, можем да ги преобразуваме от числов формат в символен формат с помощта на CAST или КОНВЕРТИРАНЕ SQL методи.

Разгледайте примера, който използва CAST метод:

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

Използване на стилове за преобразуване с CONVERT()

CONVERT() метод, за разлика от CAST() , има допълнителна опция за използване на стилове за преобразуване.

Стиловете за преобразуване са шаблони за правила, използвани в процеса на преобразуване. CONVERT() се използва най-вече в операции за дата/час. Когато данните са в нестандартен формат, те могат да се използват при преобразуване на двоични стойности. Имайте предвид, че двоичните типове данни не поддържат автоматично преобразуване на типове данни без правилни стойности на параметрите. Тогава SQL Server ще хвърли изключение.

Ако погледнем CONVERT() дефиниране на метод, виждаме, че са необходими два задължителни и един незадължителен параметър.

Първият параметър е целевият тип данни, а вторият е стойността, от която искаме да преобразуваме. Третият параметър в нашия случай може да има стойност 1 или 2 . Стойност 1 означава, че CONVERT() трябва да разглежда входния низ като шестнадесетичен низ в текстов формат и стойност 2 означава, че искате да пропуснете 0x префикс.

Разгледайте примерите, показващи това поведение:

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

Разлика между BINARY и VARBINARY

С двоични данни можем да използваме два вида типове данни – фиксиран размер и променлив размер. Или са БИНАРНИ и ВАРБИНАРНИ.

Ако използваме променливата с фиксиран размер, съдържанието винаги се разширява до определения му размер с допълване от 0x00 … – няма подпълване в променлива дължина. Използването на операция за сумиране на тези променливи не се изпълнява добавяне. Стойностите се добавят една към друга. Същото е като с типовете низове.

За да демонстрираме поведението на префикса, ще използваме два прости примера с операцията двоичен сбор:

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

Всяка стойност в оператора BINARY(2) е постфиксирана с 0x00 стойности.

Използване на целочислени стойности с двоични типове данни

SQL Server идва с вградени методи за преобразуване между числови и двоични типове. Демонстрирахме това, когато обърнахме теста низ в двоичен формат и след това обратно във формат BIGINT, без да използвате функцията ASCII():

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

Просто преобразуване между знакови и шестнадесетични стойности

За да конвертирате между чартърни и шестнадесетични стойности, е полезно да напишете персонализирана функция, която да изпълнява тази операция последователно. Един възможен подход е по-долу:

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

Този път използвахме стойността на параметъра 2 в CONVERT() функция. Показва, че тази операция не трябва да се съпоставя с ASCII код и да се показва без 0x... префикс.

Примерен казус:Съхраняване на снимки в двоичен тип на SQL Server

Обикновено подхождаме към този проблем, като внедряваме персонализирано Windows/уеб приложение или пишем персонализиран SSIS пакет с C# код. В този пример ще използвам само езика SQL. Може да бъде по-полезно, ако нямате достъп до предните инструменти на базата данни.

За да съхраняваме снимки в таблицата на базата данни, трябва да създадем таблица, която да ги съхранява. Таблицата трябва да включва колони, съдържащи името на картината и двоичното съдържание на картината:

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

За да разрешим зареждането на двоични данни в екземпляр на SQL Server, трябва да конфигурираме сървъра с две опции:

  • Активирайте опцията OLE Automation Procedures
  • Предоставяне на привилегията BulkAdmin на потребителя, изпълняващ процеса на импортиране на изображения.

Скриптът по-долу ще изпълни задачата под потребител с високи привилегии на екземпляр на 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 

Сега можем да започнем да пишем процедурата за импортиране и експортиране:

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

Сега можем да използваме тези процедури от всяко клиентско приложение по много прост начин.

Нека си представим, че имаме снимки в C:\Pictures\Inp папка. За да заредим тези снимки, трябва да изпълним следния код:

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

По подобен начин можем да експортираме данни в C:\Pictures\Out папка:

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

Заключение

Изборът между двоични обекти или алтернативни средства за съхранение на двоични данни в база данни (например съхраняване на файлови пътеки в база данни и извличането им от дисковото/облачното хранилище) зависи от множество фактори.

Общото правило е, че ако файлът е по-малък от 256 килобайта, трябва да го съхранявате в колоните VARBINARY. Ако двоичните файлове са по-големи от един мегабайт, трябва да ги съхранявате във файловата система. Ако имате FILESTREAM наличен в SQL Server версии 2008 и по-нови, той поддържа файловете под транзакционен контрол като логическа част от базата данни.

Ако решите да съхранявате двоични файлове в таблицата на SQL Server, използвайте отделна таблица само за двоично съдържание. След това можете да оптимизирате местоположението му за съхранение и да получите достъп до двигателя, вероятно като използвате отделни файлове и файлови групи за тази таблица. Подробната информация е достъпна в официалната статия на Microsoft.

Във всеки случай тествайте и двата подхода и използвайте този, който най-добре отговаря на вашите нужди.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Сравнете DATETIME и DATE, пренебрегвайки частта от времето

  2. Тригери за влизане в SQL Server

  3. Създайте параметризиран VIEW в SQL Server 2008

  4. Множество индекси срещу индекси с няколко колони

  5. 3 въпроса за наблюдение на SQL Server, които да зададете при поемане на позиция в DBA