Lưu trữ các loại khác nhau trong cùng một cột qua SQL_VARIANT
gần giống với việc truyền mọi thứ tới Object
trong .NET. Và đôi khi có những lý do hợp lệ để sử dụng loại này vì nó chắc chắn có thể cho phép cấu trúc có lập trình chung chung hơn.
Tuy nhiên, như bạn đã dự đoán, có một số cạm bẫy để sử dụng SQL_VARIANT
mà bạn cần phải nhận thức, đặc biệt là khi một trong số họ có thể là một đối phó-breaker:
Cũng giống như đúc tất cả mọi thứ để Object
trong .NET (và có thể yêu cầu boxing/unboxing tùy thuộc vào loại cơ sở), có một hit hiệu suất nhất định khi sử dụng SQL_VARIANT
. Tùy thuộc vào trường hợp sử dụng, nó có thể chấp nhận được để giảm hiệu suất nếu chức năng thực sự cần nó và/hoặc việc sử dụng không phải là rất thường xuyên (tức là nhiều lần mỗi giây).
Không giống như truyền mọi thứ tới Object
trong .NET, kiểu dữ liệu SQL_VARIANT
có giới hạn về kiểu dữ liệu cơ sở mà nó có thể chứa.Các kiểu dữ liệu sau đây không thể được lưu trữ như SQL_VARIANT
:
VARCHAR(MAX)
NVARCHAR(MAX)
VARBINARY(MAX)
XML
TIMESTAMP
/ROWVERSION
TEXT
(bạn không nên sử dụng loại này anyway tính SQL Server 2005)
NTEXT
(bạn không nên sử dụng loại này anyway như của SQL Server 2005)
IMAGE
(bạn không nên sử dụng loại này anyway như của SQL Server 2005)
Hạn chế này có thể dễ dàng ngăn chặn khả năng sử dụng SQL_VARIANT
nếu có yêu cầu lưu trữ bất kỳ loại dữ liệu nào. Xin lưu ý rằng vấn đề ở đây là các kiểu dữ liệu cơ sở và không kích thước của dữ liệu, như các xét nghiệm sau đây cho thấy:
DECLARE @tmp1 TABLE (col1 SQL_VARIANT NOT NULL);
INSERT INTO @tmp1 (col1) VALUES (CONVERT(VARCHAR(MAX), 'g'));
Returns:
Msg 206, Level 16, State 2, Line 2
Operand type clash: varchar(max) is incompatible with sql_variant
Để công bằng, một lợi ích khi sử dụng SQL_VARIANT
khi truyền mọi thứ sang NVARCHAR
là giữ nguyên thông tin loại cơ bản và thực thi việc sử dụng thông tin để bạn không thể dễ dàng lạm dụng giá trị trong ngữ cảnh hoàn toàn không phù hợp.
DECLARE @tmp2 TABLE (col1 SQL_VARIANT NOT NULL);
INSERT INTO @tmp2 (col1) VALUES (1);
SELECT CONVERT(DATETIME, col1) FROM @tmp2;
SELECT CONVERT(TIME, col1) FROM @tmp2;
Returns:
1900-01-02 00:00:00.000
Msg 529, Level 16, State 3, Line 6
Explicit conversion from data type int to time is not allowed.
Về việc không thể sử dụng SQL_VARIANT
như một PK: đây thực sự là một vấn đề không từ chính bản chất của một kiểu dữ liệu tổng quát khá nhiều không bao gồm nó từ việc mong muốn trong nơi đầu tiên cho việc sử dụng như vậy.
Về việc không thể sử dụng SQL_VARIANT
với một nhà điều hành LIKE
: đây là chủ yếu là một vấn đề không do để có thể chuyển nó sang một loại thích hợp mà làm việc với LIKE
, như trong:
WHERE CONVERT(NVARCHAR(50), [sql_variant_field]) LIKE '%something%'
Ở trên chắc chắn không phải là hiệu quả nhất, nhưng nó là chức năng, và như đã đề cập ở trên, hiệu quả đã được loại trừ vì nó đã được hy sinh để đổi lấy chức năng khi quyết định sử dụng kiểu dữ liệu SQL_VARIANT
.
Nguồn
2015-08-11 20:07:42
Tại sao bạn lưu trữ các loại khác nhau trong cùng một cột? Đây có phải là cấu trúc «EAV' không? –
Không. Tôi thực sự không muốn bị bỏ qua với hiệu lực của trường hợp sử dụng của tôi, nhưng tôi có một bảng các bộ lọc có thể được áp dụng cho các cột khác nhau. Do đó, các giá trị so sánh có các loại khác nhau. – Daniel