2011-10-20 34 views
8

Tôi đã đọc và nghe nhiều lần rằng sql_variant nên tránh. Tôi nghĩ rằng tôi có một trường hợp sử dụng tuyệt vời cho nó. Tôi đã sử dụng varchar(max) trong quá khứ để lưu trữ các loại khác nhau trong cùng một cột, nhưng có vẻ hợp lý để tránh chi phí đầu vào/tuần tự hóa khi có loại được tích hợp thực hiện chính xác những gì tôi muốn.Cạm bẫy của việc sử dụng sql_variant là gì?

Vì vậy, chính xác những gì những cạm bẫy khi sử dụng sql_variant? Chúng có liên quan đến hiệu suất, hoặc các lỗi lập trình dễ làm, hay cái gì khác? Ngẫu nhiên, tôi sẽ tương tác với cột này từ mã máy khách và các chức năng CLR, nếu đó là điều cần cân nhắc.

+0

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

+0

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

Trả lời

0

Điểm yếu duy nhất xuất hiện trong tâm trí là trong trường hợp bạn có giá trị bạn muốn đẩy vào trường sql_variant vượt quá độ dài tối đa (8016 byte, trên trang web này: http://msdn.microsoft.com/en-us/library/ms173829.aspx). Nếu giá trị của bạn không bao giờ đạt đến giới hạn đó, thì sql_variant có thể là một cách tiếp cận rất tốt. Khác, bạn vẫn có thể sử dụng sql_variant, nhưng cung cấp một trường bit "isBlob" riêng biệt trỏ đến một bảng riêng biệt với các giá trị varbinary (max) của bạn (ví dụ).

1

Tôi đã nhìn thấy cả hai vấn đề hiệu suất và chất lượng related code vấn đề:

Phần lớn thời gian bạn truy cập vào lĩnh vực này, bạn sẽ phải kiểm tra (sql_variant_property sử dụng) loại. Điều này làm cho truy vấn của bạn phức tạp hơn, điều này có thể gây ra cả hai vấn đề bạn liệt kê.

Bạn cũng sẽ phải bỏ trường này mỗi khi bạn sử dụng nó, gây thêm hình phạt về hiệu suất.

Hơn nữa, cột sql_variant không thể là một phần của khóa chính, chúng không hoạt động như một phần của cột được tính toán và chúng không hoạt động với LIKE trong mệnh đề WHERE.

1

Điều này cũng giúp việc lập trình xảy ra lỗi dễ dàng hơn. Một DBA/Programmer nhìn vào một cột và nó trông giống như một số nguyên, do đó, ông đặt một số nguyên trong nó, nhưng xa hơn xuống dòng một quá trình muốn đó là một chuỗi. Tôi đã nhìn thấy điều này với hàng nhập khẩu kém bằng văn bản vào các cột sql_variant.

1

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:

  1. 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).

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

Các vấn đề liên quan