我已经读过几次,应该避免sql_variant
。我认为我有一个很好的用例。过去我使用varchar(max)
来在同一列中存储不同的类型,但是当内建类型完全符合我的要求时,避免反序列化开销似乎是明智之举。使用sql_variant有什么缺陷?
那么究竟是什么是使用sql_variant
的陷阱?它们是与性能相关的,还是易于编程的错误,或其他?顺便说一下,如果需要考虑的话,我将从客户端代码和CLR函数与此列进行交互。
我已经读过几次,应该避免sql_variant
。我认为我有一个很好的用例。过去我使用varchar(max)
来在同一列中存储不同的类型,但是当内建类型完全符合我的要求时,避免反序列化开销似乎是明智之举。使用sql_variant有什么缺陷?
那么究竟是什么是使用sql_variant
的陷阱?它们是与性能相关的,还是易于编程的错误,或其他?顺便说一下,如果需要考虑的话,我将从客户端代码和CLR函数与此列进行交互。
想到的唯一明显的缺陷是在您想要将值推入超出其最大长度(8016字节,每个此网页:http://msdn.microsoft.com/en-us/library/ms173829.aspx)的sql_variant字段中的情况。如果你的值永远不会达到这个限制,那么sql_variant可以是一个非常好的方法。否则,您仍然可以使用sql_variant,但提供一个单独的“isBlob”位字段,指向具有varbinary(max)值(例如)的单独表格。
我已经看到了这两个性能问题和代码质量相关的问题:
你们中的大多数进入这个领域的时候,你将要检查的类型(使用SQL_VARIANT_PROPERTY)。这会使您的查询更加复杂,这可能会导致您列出的两个问题。
您每次使用时都必须投射此字段,从而导致进一步的性能损失。
此外,sql_variant列不能作为主键的一部分,它们不作为计算列的一部分工作,并且它们不能在WHERE子句中使用LIKE。
这也使编程错误更容易发生。 DBA/Programmer查看一列,它看起来像一个整数,所以他在其中放入一个整数,但是在进程想要它成为一个字符串的地方更远。我已经看到这与写入sql_variant列的写入不佳。
通过SQL_VARIANT
在同一列中存储不同类型与在.NET中将所有东西都转换为Object
几乎相同。有时使用这种类型的理由是有道理的,因为它当然可以允许更通用的程序结构。
然而,当你期待,也有一些陷阱,以使用SQL_VARIANT
,你应该知道的,尤其是他们中的一个可能是一个致命弱点:
就像铸造一切Object
在.NET中(并且可能需要根据基本类型进行装箱/拆箱),使用SQL_VARIANT
时会有明显的性能下降。根据使用情况,如果功能真正需要它并且/或者使用不是非常频繁(即每秒很多次),则降低性能可能是可接受的。
与在.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
优于将所有内容全部转换为NVARCHAR
是SQL_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_VARIANT
与LIKE
运营商:这主要是一个非的问题,由于能够将其转换为一个适当的类型,它的工作与LIKE
,如:
WHERE CONVERT(NVARCHAR(50), [sql_variant_field]) LIKE '%something%'
上述当然不是最有效的,但是它是有效的,并且如上所述,已经排除了效率,因为在决定使用数据类型时牺牲功能以换取功能。
你为什么在同一列中存储不同的类型?这是一个'EAV'结构吗? –
不,我真的不想让我的用例有效,但我有一张可应用于各种列的过滤器表。因此,可比值是不同类型的。 – Daniel