以 SQL Variant 作为列之一的非聚集索引如何工作?

How does a non-clustered index with SQL Variant as one of the columns work?

我有一个 table 包含以下列

Id - Int Primary key Identity column
Name - Varchar(100)
OrderValue - int
OrderDate - date 
OrderState - varchar(100)

列 (Name, orderValue) 具有唯一键约束和唯一非聚集索引。

我们有一个新要求,OrderValue 列将开始接收字符串、浮点数和 GUID。我们现在有两个选择,将 orderValue 的数据类型更改为 Varchar(100) 或 SQL_Variant。我的队友都赞成sql_variant。他们的理由是,由于 orderValue 是唯一非聚集索引的一部分,因此更改它 sql_variant 将使索引 table 中的索引键的排序变得容易,因为相同类型的所有数据类型都存储在一起.我不太熟悉 Sql_variant 以及如何为 sql_variant 存储索引,但我读到 sql_variant 的性能通常很差。在我们的例子中,什么是好的选择?当非聚集索引的其中一列为 sql_variant?

时,它们如何工作

我自己从未使用过这种数据类型。

更新:

找到一篇演示如何使用 SQL_VARIANT 数据类型的文章:https://aboutsqlserver.com/2012/02/22/store-custom-fieldsattributes-in-microsoft-sql-server-database-part-2-namevalue-pairs/?unapproved=201416&moderation-hash=771c41a02ff9a7c909e93140a8795e3a#comment-201416

订购

从阅读 documentation, specifically value comparison part 我可以看出在某些情况下排序看起来不“自然”,例如

CREATE TABLE #Test( a SQL_VARIANT )
INSERT INTO #Test VALUES( 2 ) -- INT
INSERT INTO #Test VALUES( 2.1 ) -- DECIMAL
INSERT INTO #Test VALUES( '3' ) -- VARCHAR
INSERT INTO #Test VALUES( CAST( 1.8 AS FLOAT ) )
INSERT INTO #Test VALUES( DATEFROMPARTS( 2020, 1, 1 ) )
SELECT *, SQL_VARIANT_PROPERTY ( a , 'BaseType' ) FROM #Test ORDER BY a
DROP TABLE #Test

结果(按列 a 升序排列):

a                          
-------------------------- -----------
3                          varchar
2                          int
2.1                        numeric
1.8                        float
2020-01-01 00:00:00.000    date

指数表现

我认为索引查找不会有任何性能问题。插入和更新可能会受到惩罚

陷阱

使用这种数据类型时会遇到很多小问题。下面是一些示例:

1| WHERE 条件将不匹配,除非数据类型匹配:

-- Returns nothing
SELECT *, SQL_VARIANT_PROPERTY ( a , 'BaseType' ), SQL_VARIANT_PROPERTY ( a , 'TotalBytes' )
FROM #Test
WHERE a = '2'
ORDER BY a

-- Returns nothing
SELECT *, SQL_VARIANT_PROPERTY ( a , 'BaseType' ), SQL_VARIANT_PROPERTY ( a , 'TotalBytes' )
FROM VariantTest
WHERE a = 3
ORDER BY a

2|这不会插入具有正确数据类型的数据,因为数据类型将首先隐式转换为 VARCHAR,然后再转换为 SQL_VARIANT:

INSERT INTO #Test VALUES( 2 ), ( 2.1 ), ( '3' ), CAST( 1.8 AS FLOAT )