通过SQL_VARIANT 将不同类型存储在同一列中几乎与在.NET 中将所有内容转换为Object 相同。有时使用这种类型是有正当理由的,因为它当然可以允许更通用的编程结构。
但是,正如您所预料的那样,您应该注意使用 SQL_VARIANT 的一些陷阱,尤其是其中一个可能会破坏交易:
就像在 .NET 中将所有内容都强制转换为 Object(并且可能需要根据基本类型进行装箱/拆箱),使用 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 开始,您不应该使用这种类型)
-
IMAGE(从 SQL Server 2005 开始,您不应该使用这种类型)
如果需要存储这些数据类型中的任何一个,此限制可以很容易地阻止使用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%'
上述当然不是最有效的,但它是功能性的,如上所述,效率已经被排除在外,因为在决定使用 SQL_VARIANT 数据类型时牺牲了功能性。