预读和 SQL-Variant 字段

got*_*tqn 6 sql-server sql-server-2012 sql-variant-property sql-server-2014 standard-edition

我有两个包含完全相同数据的表。两个表都有bigint primary key identity column60 列和 300 000 行。不同之处在于第二个表的所有列都有sql-variant类型。

我正在创建临时表并从其中的两个表中导入数据。当从sql-variant列中提取数据时,它会被转换为相应的 SQL 类型。

从第一个表中提取数据是针对1 sec和从第二个表中提取的6 secs

基本上,执行的差异在于估计:

在此处输入图片说明

在此处输入图片说明

并在read-ahead reads计数中:

在此处输入图片说明 在此处输入图片说明

我想知道为什么SQL Server不能提前加载从sql-variant字段中读取的数据(几乎没有read-ahead reads)。

此外,表的存储大小几乎相同:

在此处输入图片说明

为什么SQL Server认为它应该阅读67 GB


列类型是:

16 x BIGINT
8  x DECIMAL(9,2)
36 x NVARCHAR(100)
Run Code Online (Sandbox Code Playgroud)

dbcc dropcleanbuffers命令每次在数据提取和填充之前使用。


为了进行测试,您可以从这里下载示例数据文件。然后,

  1. 执行 Tech05_01_TableDefinitions.sql
  2. 执行 3 次 Tech05_02_TablePupulation.sql
  3. 打开Tech05_03_TestingInsertionInTempTable.sql文件并像这样执行一次:

    DECLARE @TableStructured SYSNAME = '[dbo].[NormalDataTypes_60Cols]';
    DECLARE @TableFromWhichDataIsCoppied SYSNAME = '[dbo].[SQLVariant01_60Cols]';
    
    Run Code Online (Sandbox Code Playgroud)

    有一次是这样的:

    DECLARE @TableStructured SYSNAME = '[dbo].[NormalDataTypes_60Cols]';
    DECLARE @TableFromWhichDataIsCoppied SYSNAME = '[dbo].[NormalDataTypes_60Cols]';
    
    Run Code Online (Sandbox Code Playgroud)

Joe*_*ish 6

Tech05_03_TestingInsertionInTempTable.sql 文件存在一些问题。它使用一个未定义的名为 [dbo].[ConcatenateWithOrder] 的函数。我想我理解您的意图并对其进行调整以生成一些插入语句。

要回答您的第一个问题,SQL Server 不能使用预读来获取 sql_variant 数据是不正确的。如果我DBCC DROPCLEANBUFFERS;在插入之前立即运行,我会从 statistics io 中得到以下输出:

表“SQLVariant01_60Cols”。扫描计数 1,逻辑读 66311,物理读 3,预读 66307,lob 逻辑读 0,lob 物理读 0,lob 预读 0。

要回答有关计划中估计行大小的第二个问题,SQL Server 不会查看表使用的空间并除以行数。相反,查询计划包含基于表中数据类型的估计。有关更多详细信息,请阅读Martin Smith 的这篇文章

SQL Server 估计您的表的行大小为 235 KB。我可以接近那个:

240484.0 = 0.5 * (8016 * 60 + 8)

这与 235 KB 略有不同,但我不知道 sql_variants 的空间估计是如何准确计算的。但是您可以看到,当使用可以存储许多不同数据类型的数据类型时,您可能会高估。为了记录,我认为估计与您观察到的性能问题没有任何关系。

为了回答我认为您想问的问题(为什么使用 sql_variant 的查询比其他查询慢得多?),我对其进行了一些测试,从 sql_variant 表中进行选择时似乎存在大量 CPU 开销。我选择了行而不是插入它们(在它们到达客户端之前丢弃它们)并发现 cpu 时间有显着差异。sql_variant 查询的 CPU 时间为 3151 毫秒,总运行时间为 3268 毫秒。另一个查询的 CPU 时间为 686 毫秒,总运行时间为 744 毫秒。CPU 时间的差异几乎完全解释了运行时间的差异。

使用 sql_variant 列时存在开销似乎不是不合理的,对吗?我不知道有什么技巧可以避免支付开销。如果您觉得您的数据模型需要 sql_variant 列,我只能建议进行测试以确保您可以获得足够好的性能。