Remus有益地指出,VARCHAR
列的最大长度会影响估计的行大小,因此会影响SQL Server提供的内存授予。
我尝试做更多的研究,以扩展他的回答的“从此开始”。我没有完整或简洁的解释,但这是我所发现的。
复制脚本
我创建了一个完整的脚本,该脚本生成一个伪造的数据集,在该数据集上创建索引所需的时间大约是我的机器上该VARCHAR(256)
版本的10倍。所使用的数据是完全一样的,但在第一表使用的实际最大长度18
,75
,9
,15
,123
,和5
,而所有列使用的最大长度256
在所述第二表中。
键入原始表
在这里,我们看到原始查询在大约20秒内完成,并且逻辑读取等于表的大小~1.5GB
(195K页,每页8K)。
-- CPU time = 37674 ms, elapsed time = 19206 ms.
-- Table 'testVarchar'. Scan count 9, logical reads 194490, physical reads 0
CREATE CLUSTERED INDEX IX_testVarchar
ON dbo.testVarchar (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
键控VARCHAR(256)表
为了 VARCHAR(256)
表,我们看到经过时间已大大增加。
有趣的是,CPU时间和逻辑读取都不会增加。鉴于表具有完全相同的数据,这是有道理的,但是并不能解释为什么经过时间如此之慢。
-- CPU time = 33212 ms, elapsed time = 263134 ms.
-- Table 'testVarchar256'. Scan count 9, logical reads 194491
CREATE CLUSTERED INDEX IX_testVarchar256
ON dbo.testVarchar256 (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO
I / O和等待状态:原始
如果捕获更多细节(使用p_perfMon,我编写了一个过程),我们可以看到绝大多数I / O是在LOG
文件上执行的。我们在实际的ROWS
(主数据文件)上看到相对较少的I / O ,主要的等待类型是LATCH_EX
,这表明内存中的页面争用。
根据保罗·兰德尔(Paul Randal)的说法,我们还可以看到我的旋转磁盘介于“坏”和“令人震惊地糟糕”之间:)
I / O和等待状态:VARCHAR(256)
为了 VARCHAR(256)
版本,I / O和等待状态看起来完全不同!在这里,我们看到数据文件(ROWS
)上I / O的大量增加,并且停顿时间现在使Paul Randal简单地说“哇!”。
#1等待类型现在是毫不奇怪的IO_COMPLETION
。但是为什么会产生那么多的I / O?
实际查询计划:VARCHAR(256)
从查询计划中,我们可以看到Sort
运算符VARCHAR(256)
在查询版本中具有递归溢出(深度5级!)。(原始版本完全没有溢出。)
实时查询进度:VARCHAR(256)
我们可以使用sys.dm_exec_query_profiles来查看SQL 2014+中的实时查询进度。在原始版本中,整个Table Scan
和Sort
处理都没有任何溢出(spill_page_count
始终保留0
)。
VARCHAR(256)
但是,在该版本中,我们可以看到页面溢出为Sort
操作员迅速积累。这是查询完成前的查询进度的快照。此处的数据跨所有线程聚合。
如果我分别研究每个线程,我会看到2个线程在大约5秒钟内完成了排序(在表扫描上花费了15秒钟之后,整体@ 20秒钟)。如果所有线程都以该速率进行,则VARCHAR(256)
索引创建将在与原始表大致相同的时间内完成。
但是,其余6个线程的进度要慢得多。这可能是由于内存的分配方式以及线程在溢出数据时被I / O阻止的方式所致。我不确定。
你能做什么?
您可以考虑尝试以下几种方法:
- 与供应商合作以回滚到以前的版本。如果无法做到这一点,请让您对此更改不满意的供应商,以便他们可以考虑在将来的版本中还原它。
- 当添加索引,可以考虑使用
OPTION (MAXDOP X)
其中X
一个较小的数字比目前的服务器级别设置。当我OPTION (MAXDOP 2)
在计算机上使用此特定数据集时,VARCHAR(256)
版本在25 seconds
(相比之下,使用8个线程需要3-4分钟!)。较高的并行度可能会加剧溢出行为。
- 如果有可能进行额外的硬件投资,请在系统上分析I / O(可能的瓶颈),并考虑使用SSD来减少因溢出而导致的I / O延迟。
进一步阅读
保罗·怀特(Paul White)撰写了一篇不错的博客文章,介绍了可能感兴趣的SQL Server内部结构。它确实谈到了溢出,线程偏斜和并行排序的内存分配。