Giới thiệu
Công việc hàng ngày hiếm khi yêu cầu lưu trữ dữ liệu nhị phân trực tiếp vào các cột cơ sở dữ liệu. Tuy nhiên, nó rất hữu ích trong một số trường hợp.
Trái ngược với quan điểm phổ biến, mảng byte có thể giúp ích nhiều hơn là chỉ lưu trữ các đối tượng nhị phân lớn (tài liệu, đa phương tiện, v.v.). Ngoài ra, chúng có thể được sử dụng để lưu trữ các giá trị băm và dữ liệu mẫu để tìm kiếm nhanh hơn / phân tích cấp cao. Hoặc, chúng có thể chứa các byte ở trạng thái BẬT / TẮT trong một số rơle điện tử. Ngay khi chúng ta bắt đầu nghĩ về dữ liệu phần cứng được lưu trữ trong cơ sở dữ liệu, các ứng dụng trở nên rõ ràng hơn.
Không giống như kiểu dữ liệu VARCHAR nơi bạn phải xử lý các trang đối chiếu và mã, kiểu dữ liệu nhị phân là chuỗi byte (đôi khi được gọi là mảng byte trong ngôn ngữ lập trình hướng đối tượng), có kích thước cố định (BINAR) hoặc biến (VARBINAR).
Để hiểu chi tiết hơn về các loại nhị phân, trước tiên chúng tôi sẽ giới thiệu ngắn gọn về số thập lục phân, đó là cách dữ liệu này được lưu trữ nội bộ.
Số thập lục phân
Nếu bạn đã bỏ qua lớp học về số thập lục phân ở trường trung học, bạn có thể tìm thấy phần giới thiệu hay trên trang Wikipedia chuyên dụng. Ở đó, bạn có thể làm quen với định dạng đánh số này.
Để hiểu bài viết này, điều quan trọng cần biết là SQL Server Management Studio hiển thị dữ liệu nhị phân ở định dạng thập lục phân với tiền tố “0x”.
Không có sự khác biệt lớn giữa định dạng đánh số thập lục phân và thập phân. Định dạng thập lục phân sử dụng dấu cơ số 16 (0-9 và A-F) thay vì cơ số 10 của ký hiệu thập phân (0-9). Giá trị A-F là các số 10-15 từ ký hiệu đánh số thập phân.
Đây là lý do tại sao chúng tôi sử dụng ký hiệu thập lục phân. Vì một byte chứa 8 bit, cho phép 256 số nguyên rời rạc, nên sẽ có lợi khi trình bày các byte ở định dạng hex. Nếu chúng tôi đang nhắm mục tiêu phạm vi 0-256, nó được biểu thị dưới dạng 00-FF trong ký hiệu thập lục phân. Tiền tố trong Studio quản lý là để đọc rõ ràng, nhấn mạnh rằng chúng tôi đang hiển thị số thập lục phân chứ không phải mặc định giá trị thập phân.
Chuyển đổi giá trị thủ công bằng CAST ()
Vì các giá trị nhị phân, theo nghĩa chặt chẽ, là chuỗi, chúng tôi có thể chuyển đổi chúng từ định dạng số sang ký tự bằng cách sử dụng CAST hoặc CHUYỂN ĐỔI Các phương thức SQL.
Hãy xem ví dụ sử dụng CAST phương pháp:
SELECT CAST('HexTest' AS VARBINARY);
SELECT CAST(0x48657854657374 AS VARCHAR);
Sử dụng kiểu chuyển đổi với CONVERT ()
CHUYỂN ĐỔI () , không giống như CAST () , có một tùy chọn bổ sung để sử dụng các kiểu chuyển đổi.
Kiểu chuyển đổi là các mẫu cho các quy tắc được sử dụng trong quá trình chuyển đổi. CHUYỂN ĐỔI () hầu hết được sử dụng trong các hoạt động ngày / giờ. Khi dữ liệu ở định dạng không chuẩn, nó có thể được sử dụng trong chuyển đổi giá trị nhị phân. Lưu ý rằng các kiểu dữ liệu nhị phân không hỗ trợ chuyển đổi kiểu dữ liệu tự động mà không có các giá trị tham số thích hợp. Sau đó, SQL Server sẽ đưa ra một ngoại lệ.
Nếu chúng ta nhìn vào CONVERT () định nghĩa phương thức, chúng tôi thấy nó có hai tham số bắt buộc và một tham số tùy chọn.
Tham số đầu tiên là kiểu dữ liệu đích và tham số thứ hai là giá trị mà chúng tôi muốn chuyển đổi từ đó. Tham số thứ ba, trong trường hợp của chúng tôi, có thể có giá trị 1 hoặc 2 . Giá trị 1 có nghĩa là CONVERT () nên coi chuỗi đầu vào là chuỗi thập lục phân ở định dạng văn bản và giá trị 2 có nghĩa là bạn muốn bỏ qua 0x tiền tố.
Hãy xem các ví dụ hiển thị hành vi đó:
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);
Sự khác biệt giữa BINARY và VARBINARY
Với dữ liệu nhị phân, chúng ta có thể sử dụng hai loại kiểu dữ liệu - kích thước cố định và kích thước thay đổi. Hoặc chúng là BINARY và VARBINARY.
Nếu chúng tôi sử dụng biến kích thước cố định, nội dung luôn được mở rộng đến kích thước xác định với phần đệm 0x00 … - không có phần đệm có độ dài thay đổi. Việc sử dụng hoạt động tính tổng trên các biến này không có phép cộng nào được thực thi. Các giá trị được nối với nhau. Điều này cũng tương tự như với các loại chuỗi.
Để chứng minh hành vi tiền tố, chúng tôi sẽ sử dụng hai ví dụ đơn giản với phép toán tổng nhị phân:
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));
Mỗi giá trị trong câu lệnh BINARY (2) được cố định bằng 0x00 giá trị.
Sử dụng giá trị số nguyên với kiểu dữ liệu nhị phân
SQL Server đi kèm với các phương thức tích hợp để chuyển đổi giữa các kiểu số và kiểu nhị phân. Chúng tôi đã chứng minh điều này khi chúng tôi quay Thử nghiệm chuỗi thành định dạng nhị phân, rồi quay lại định dạng BIGINT mà không cần sử dụng hàm ASCII ():
SELECT CAST('Test' AS VARBINARY(MAX));
SELECT CAST(CAST('Test' AS VARBINARY(MAX)) AS BIGINT);
Chuyển đổi đơn giản giữa các giá trị ký tự và hệ thập lục phân
Để chuyển đổi giữa các giá trị điều lệ và hệ thập lục phân, rất hữu ích khi viết một hàm tùy chỉnh sẽ thực hiện thao tác này một cách nhất quán. Dưới đây là một cách tiếp cận khả thi:
-- 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')
Lần này, chúng tôi đã sử dụng giá trị tham số 2 trong CONVERT () hàm số. Nó cho thấy rằng thao tác này không nên được ánh xạ tới mã ASCII và được hiển thị mà không có 0x… tiền tố.
Ví dụ về Nghiên cứu điển hình:Lưu trữ ảnh trong kiểu nhị phân của SQL Server
Chúng tôi thường tiếp cận vấn đề này bằng cách triển khai ứng dụng web / cửa sổ tùy chỉnh hoặc viết gói SSIS tùy chỉnh với mã C #. Trong ví dụ này, tôi sẽ chỉ sử dụng ngôn ngữ SQL. Nó có thể hữu ích hơn nếu bạn không có quyền truy cập vào các công cụ giao diện người dùng của cơ sở dữ liệu.
Để lưu trữ ảnh trong bảng cơ sở dữ liệu, chúng ta cần tạo một bảng chứa chúng. Bảng phải bao gồm các cột chứa tên ảnh và nội dung nhị phân của ảnh:
-- 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
Để cho phép tải dữ liệu nhị phân vào phiên bản SQL Server, chúng ta cần định cấu hình máy chủ với hai tùy chọn:
- Bật tùy chọn Quy trình tự động hóa OLE
- Gán đặc quyền BulkAdmin cho người dùng đang thực hiện quy trình nhập hình ảnh.
Tập lệnh bên dưới sẽ thực hiện tác vụ với người dùng có đặc quyền cao của phiên bản 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
Bây giờ chúng ta có thể bắt đầu viết thủ tục xuất nhập:
-- 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
Giờ đây, chúng tôi có thể sử dụng các quy trình này từ bất kỳ ứng dụng khách nào một cách rất đơn giản.
Hãy tưởng tượng chúng ta có hình ảnh trong C:\ Pictures \ Inp thư mục. Để tải những hình ảnh này, chúng ta cần thực thi đoạn mã sau:
-- Load picture to table row
exec dbo.proc_ImportBinary ‘MyPic’, ‘C:\Pictures\Inp’, ‘MyPic.jpg’
Theo cách tương tự, chúng tôi có thể xuất dữ liệu sang C:\ Pictures \ Out thư mục:
exec dbo.proc_ExportBinary ‘MyPic’, ‘C:\Pictures\Out’, ‘MyPic.jpg’
Kết luận
Sự lựa chọn giữa các đối tượng nhị phân hoặc các phương tiện thay thế để lưu trữ dữ liệu nhị phân trong cơ sở dữ liệu (ví dụ:lưu trữ đường dẫn tệp trong cơ sở dữ liệu và truy xuất chúng từ đĩa / lưu trữ đám mây) phụ thuộc vào nhiều yếu tố.
Quy tắc chung là nếu tệp có kích thước nhỏ hơn 256 kilobyte, bạn nên lưu trữ nó trong các cột VARBINARY. Nếu tệp nhị phân lớn hơn một megabyte, bạn nên lưu trữ chúng trên hệ thống tệp. Nếu bạn có sẵn FILESTREAM trong SQL Server phiên bản 2008 trở lên, nó sẽ giữ các tệp dưới sự kiểm soát giao dịch như một phần hợp lý của cơ sở dữ liệu.
Nếu bạn quyết định lưu trữ các tệp nhị phân trong bảng SQL Server, chỉ sử dụng một bảng riêng cho nội dung nhị phân. Sau đó, bạn có thể tối ưu hóa vị trí lưu trữ của nó và truy cập vào công cụ, có thể bằng cách sử dụng Tệp và Nhóm tệp riêng biệt cho bảng này. Thông tin chi tiết có trong bài viết chính thức của Microsoft.
Trong mọi trường hợp, hãy thử nghiệm cả hai cách tiếp cận và sử dụng cách phù hợp nhất với nhu cầu của bạn.