【问题标题】:How does a non-clustered index with SQL Variant as one of the columns work?以 SQL Variant 作为列之一的非聚集索引如何工作?
【发布时间】:2021-12-08 16:03:34
【问题描述】:

我有一个包含以下列的表格

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 将使索引表中的索引键的排序变得容易,因为相同类型的所有数据类型都存储在一起。我不太熟悉 Sql_variant 以及如何为 sql_variants 存储索引,但我读过 sql_variant 的性能通常很差。在我们的例子中,什么是一个好的选择?当非聚集索引具有其中一列作为 sql_variant 时,它们如何工作?

【问题讨论】:

  • 我可能会保留 OrderValue 原样并添加/使用新的/不同的字段来存储字符串变体作为参考。
  • SQL 是强类型的,仅仅因为你可以,并不意味着你应该。一个变体可以被索引,但大小是有限的(900b),超过这个值并且插入会出错。我会为每种特定的数据类型添加列。
  • 感谢大家的回复。我们预计任何时候都不会超过 900b,我们希望所有值都在 Ordervalue 中。我们无法为每种数据类型创建新列,因为我们预计未来会有更多的数据类型。从性能的角度来看,将此列转换为 sql_variant 或 varchar 是否有意义?
  • 可能还有多少数据类型? EAV 远没有 sql_variant 恕我直言邪恶。 sqlblog.org/2009/11/19/what-is-so-bad-about-eav-anyway
  • 还要继续抨击 sql_variant,请参阅 thisthisthisthisthisthis。有这么多人警告这种数据类型,可能会出什么问题?它一直是“加油站寿司”

标签: sql sql-server tsql ssis msbi


【解决方案1】:

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

更新:

发现一篇文章演示了使用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,特别是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

结果(按 col 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 )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-07
    • 2021-04-10
    • 2011-05-21
    • 1970-01-01
    • 2021-09-23
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多