简体   繁体   English

使用sql_variant有哪些陷阱?

[英]What are the pitfalls of using sql_variant?

I've read and heard several times that sql_variant should be avoided. 我读过几次,应该避免使用sql_variant I think I have a great use case for it. 我认为我有一个很好的用例。 I've used varchar(max) in the past to store different types in the same column, but it seems sensible to avoid the de/serialization overhead when there's a built-in type that does exactly what I want. 我过去曾使用varchar(max)将不同类型存储在同一列中,但是当有一个内置类型可以完全满足我的需要时,避免进行反序列化开销似乎很明智。

So, what exactly are the pitfalls of using sql_variant ? 那么,使用sql_variant的陷阱到底什么呢? Are they performance related, or easy-to-make programming mistakes, or something else? 它们是与性能相关的,还是容易犯的编程错误,还是其他原因? Incidentally, I'll be interacting with this column from client code and CLR functions, if that's something to consider. 顺便说一句,如果需要考虑的话,我将与客户机代码和CLR函数中的该列进行交互。

Storing different types in the same column via SQL_VARIANT is almost the same thing as casting everything to Object in .NET. 通过SQL_VARIANT将不同类型存储在同一列中与将所有内容强制转换为.NET中的Object几乎是同一件事。 And sometimes there are valid reasons for using this type as it can certainly allow for a more generic programmatic structure. 有时有使用这种类型的正当理由,因为它肯定可以允许使用更通用的程序结构。

However, as you were anticipating, there are some pitfalls to using SQL_VARIANT that you should be aware of, especially as one of them might be a deal-breaker: 但是,正如您所预期的那样,使用SQL_VARIANT要注意一些陷阱,尤其是其中之一可能会破坏交易:

  1. Just like casting everything to Object in .NET (and possibly requiring boxing / unboxing depending on the base type), there is a definite performance hit when using SQL_VARIANT . 就像将所有内容都投射到.NET中的Object (并且可能需要根据基本类型进行装箱/拆箱)一样,使用SQL_VARIANT性能产生一定的SQL_VARIANT Depending on the use case, it might be acceptable to have reduced performance if the functionality really needs it and/or the usage is not very frequent (ie many times per second). 根据使用情况,如果功能确实需要它和/或使用不是很频繁(即每秒多次),则可以降低性能。

  2. Unlike casting everything to Object in .NET, the SQL_VARIANT datatype has limitations on what base datatypes it can contain. 与将所有内容强制转换为.NET中的Object不同, SQL_VARIANT数据类型在可包含的基本数据类型方面有限制。 The following datatypes cannot be stored as SQL_VARIANT : 以下数据类型不能存储为SQL_VARIANT

    • VARCHAR(MAX)
    • NVARCHAR(MAX)
    • VARBINARY(MAX)
    • XML
    • TIMESTAMP / ROWVERSION TIMESTAMP / ROWVERSION
    • TEXT (you shouldn't be using this type anyway as of SQL Server 2005) TEXT (从SQL Server 2005开始,您无论如何都不应使用此类型)
    • NTEXT (you shouldn't be using this type anyway as of SQL Server 2005) NTEXT (从SQL Server 2005开始,您无论如何都不应使用此类型)
    • IMAGE (you shouldn't be using this type anyway as of SQL Server 2005) IMAGE (从SQL Server 2005开始,您不应该使用这种类型)

    This limitation can easily prevent the possibility of using SQL_VARIANT if there is a requirement to store any of these datatypes. 如果需要存储任何这些数据类型,此限制可以轻松防止使用SQL_VARIANT的可能性。 Please note that the issue here is the base datatype and not the size of the data, as the following test shows: 请注意,这里的问题是基本数据类型,而不是数据大小,如以下测试所示:

     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 

To be fair, one benefit to using SQL_VARIANT over casting everything to NVARCHAR is that SQL_VARIANT retains the underlying type info and enforces its usage so that you cannot easily misuse values in completely inappropriate contexts. 公平地说,使用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;

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.

Regarding not being able to use SQL_VARIANT as a PK: this is really a non-issue since the very nature of a generic datatype pretty much excludes it from being desirable in the first place for such a use. 关于不能将SQL_VARIANT用作PK:这确实不是问题,因为通用数据类型的本质几乎将其排除在这种用途的首位。

Regarding not being able to use SQL_VARIANT with a LIKE operator: this is mostly a non-issue due to being able to convert it to an appropriate type that does work with LIKE , as in: 关于不能将SQL_VARIANTLIKE运算符一起使用:这主要是非问题,因为能够将其转换为可与LIKE一起使用的适当类型,如:

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

The above is certainly not the most efficient, but it is functional, and as mentioned above, efficiency was already ruled out as it was sacrificed in return for functionality when deciding to use the SQL_VARIANT datatype. 上面的内容当然不是最有效的,但是它是功能性的,并且如上所述,效率已经被排除在外,因为在决定使用SQL_VARIANT数据类型时牺牲了它来换取功能性。

It also makes it easier for programming errors to occur. 这也使编程错误更容易发生。 A DBA/Programmer looks at a column and it looks like a integer, so he puts an integer in it, but farther down the line a process wants that to be a string. DBA /程序员会查看一列,它看起来像是整数,因此他在其中放入了一个整数,但是在更深的地方,进程希望将其作为字符串。 I've seen this with poorly written imports into sql_variant columns. 我已经看到导入到sql_variant列中的写入不正确的情况。

I've seen both performance problems and code quality related problems: 我已经看到了性能问题和与代码质量相关的问题:

Most of the time you access this field, you are going to have to check the type (using sql_variant_property). 在大多数情况下,访问该字段时,您将不得不检查类型(使用sql_variant_property)。 This makes your queries more complex, which can cause both of the problems you list. 这会使您的查询更加复杂,从而可能导致您列出的两个问题。

You will also have to cast this field every time you use it, causing further performance penalty. 您还必须在每次使用此字段时都强制转换此字段,这会导致进一步的性能损失。

Further, sql_variant columns cant be part of a primary key, they don't work as part of a computed column, and they don't work with LIKE in a WHERE clause. 此外,sql_variant列不能成为主键的一部分,它们不能作为计算列的一部分,并且不能与WHERE子句中的LIKE一起使用。

The only obvious pitfall that comes to mind is in situations wherein you have values that you want to push into your sql_variant field that exceed its max length (8016 bytes, per this web page: http://msdn.microsoft.com/en-us/library/ms173829.aspx ). 想到的唯一明显的陷阱是在某些情况下,您希望将值推入sql_variant字段,该值超过了其最大长度(每个网页8016字节): http : //msdn.microsoft.com/zh-我们/library/ms173829.aspx )。 If your values never approach that limit, then sql_variant can be a very good approach. 如果您的值从未达到该限制,那么sql_variant可能是一个很好的方法。 Else, you could still use sql_variant, but provide a separate "isBlob" bit field that points to a separate table with your varbinary(max) values (for eg). 否则,您仍然可以使用sql_variant,但是提供一个单独的“ isBlob”位字段,该字段指向带有您的varbinary(max)值的单独表(例如)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM