2011-10-20 71 views
8

我已經讀過幾次,應該避免sql_variant。我認爲我有一個很好的用例。過去我使用varchar(max)來在同一列中存儲不同的類型,但是當內建類型完全符合我的要求時,避免反序列化開銷似乎是明智之舉。使用sql_variant有什麼缺陷?

那麼究竟是什麼使用sql_variant的陷阱?它們是與性能相關的,還是易於編程的錯誤,或其他?順便說一下,如果需要考慮的話,我將從客戶端代碼和CLR函數與此列進行交互。

+0

你爲什麼在同一列中存儲不同的類型?這是一個'EAV'結構嗎? –

+0

不,我真的不想讓我的用例有效,但我有一張可應用於各種列的過濾器表。因此,可比值是不同類型的。 – Daniel

回答

0

想到的唯一明顯的缺陷是在您想要將值推入超出其最大長度(8016字節,每個此網頁:http://msdn.microsoft.com/en-us/library/ms173829.aspx)的sql_variant字段中的情況。如果你的值永遠不會達到這個限制,那麼sql_variant可以是一個非常好的方法。否則,您仍然可以使用sql_variant,但提供一個單獨的「isBlob」位字段,指向具有varbinary(max)值(例如)的單獨表格。

1

我已經看到了這兩個性能問題和代碼質量相關的問題:

你們中的大多數進入這個領域的時候,你將要檢查的類型(使用SQL_VARIANT_PROPERTY)。這會使您的查詢更加複雜,這可能會導致您列出的兩個問題。

您每次使用時都必須投射此字段,從而導致進一步的性能損失。

此外,sql_variant列不能作爲主鍵的一部分,它們不作爲計算列的一部分工作,並且它們不能在WHERE子句中使用LIKE。

1

這也使編程錯誤更容易發生。 DBA/Programmer查看一列,它看起來像一個整數,所以他在其中放入一個整數,但是在進程想要它成爲一個字符串的地方更遠。我已經看到這與寫入sql_variant列的寫入不佳。

1

通過SQL_VARIANT在同一列中存儲不同類型與在.NET中將所有東西都轉換爲Object幾乎相同。有時使用這種類型的理由是有道理的,因爲它當然可以允許更通用的程序結構。

然而,當你期待,也有一些陷阱,以使用SQL_VARIANT,你應該知道的,尤其是他們中的一個可能是一個致命弱點:

  1. 就像鑄造一切Object在.NET中(並且可能需要根據基本類型進行裝箱/拆箱),使用SQL_VARIANT時會有明顯的性能下降。根據使用情況,如果功能真正需要它並且/或者使用不是非常頻繁(即每秒很多次),則降低性能可能是可接受的。

  2. 與在.NET中將所有東西都轉換爲Object不同,SQL_VARIANT數據類型對其可包含的基本數據類型有限制。下面的數據類型不能被存儲爲SQL_VARIANT

    • VARCHAR(MAX)
    • NVARCHAR(MAX)
    • VARBINARY(MAX)
    • XML
    • TIMESTAMP/ROWVERSION
    • TEXT(你不應該無論如何使用這種類型的SQL Server 2005)
    • NTEXT(反正你不應該使用這種類型的SQL Server 2005中的)(你不應該無論如何使用這種類型的SQL Server 2005)
    • IMAGE

    這種限制可以很容易地防止如果需要存儲任何這些數據類型,則可以使用SQL_VARIANT。請注意,這裏的問題是基本數據類型和的數據的大小,如下面的測試表明:

    DECLARE @tmp1 TABLE (col1 SQL_VARIANT NOT NULL); 
    INSERT INTO @tmp1 (col1) VALUES (CONVERT(VARCHAR(MAX), 'g')); 
    

    返回:

    Msg 206, Level 16, State 2, Line 2 
    Operand type clash: varchar(max) is incompatible with sql_variant 
    

爲了公平起見,一個使用SQL_VARIANT優於將所有內容全部轉換爲NVARCHARSQL_VARIANT保留了底層的類型信息並強制使用它,以便您不會在完全不合適的上下文中輕易地誤用值。

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; 

返回:

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. 

對於不能夠使用SQL_VARIANT作爲PK:這是真的,因爲一個通用數據類型的本質是個問題幾乎排除了它是在理想這種用途的第一位。

對於不能夠使用SQL_VARIANTLIKE運營商:這主要是一個非的問題,由於能夠將其轉換爲一個適當的類型,它的工作與LIKE,如:

WHERE CONVERT(NVARCHAR(50), [sql_variant_field]) LIKE '%something%' 

上述當然不是最有效的,但是它是有效的,並且如上所述,已經排除了效率,因爲在決定使用數據類型時犧牲功能以換取功能。

相關問題