排序溢出和随机基数估计的阈值

dew*_*wet 3 sql-server optimization sorting sql-server-2014 query-performance

我想测试 tempdb 溢出警告,所以我在 SQL Server 2014 上运行以下脚本:

USE tempdb

IF OBJECT_ID('tempdb..tblTest') IS NOT NULL DROP TABLE tblTest

CREATE TABLE tblTest
(
          c1 INT         PRIMARY KEY CLUSTERED,
          c2 INT        ,
          c3 CHAR (1000)
);

GO
SET NOCOUNT ON;

BEGIN TRANSACTION;

DECLARE @i AS INT;

SET @i = 1;

WHILE @i <= 10000
          BEGIN
                    INSERT  INTO tblTest (c1, c2, c3)
                    VALUES              (@i, @i, 'a');
                    SET @i = @i + 1;
          END

COMMIT TRANSACTION;

GO
UPDATE STATISTICS dbo.tblTest
GO
SET STATISTICS XML ON;
GO
--no tempdb spill (SQL Server 2014)
--in sql server 2012 always different "Estimated number of rows" if you run the whole script several times
SELECT   *
FROM     tblTest
WHERE    c1 <= 5948
ORDER BY c2
OPTION (MAXDOP 1);

GO
SET STATISTICS XML OFF;

SET STATISTICS XML ON;
GO
--no tempdb spill (SQL Server 2014)
SELECT   *
FROM     tblTest
WHERE    c1 <= 5949
ORDER BY c2
OPTION (MAXDOP 1);

GO
SET STATISTICS XML OFF;
Run Code Online (Sandbox Code Playgroud)

(查询的核心是基于 MS 的一种材料)

1) 我好奇的第一件事是在 c1 列的这个特定级别的排序操作期间是什么导致 tempdb 溢出。所有估计都是正确的,并且两个查询的读取页数相同。那么为什么第二个查询会溢出呢?(换句话说,为什么后面查询的内存授予要高得多)。

2) 我已经在 SQL Server 2012 上测试了这个查询并且得到了非常有趣的行为。首先,我无法达到相同的阈值,所以我反复运行脚本并注意到估计的行数总是与上次运行时的不同。我的问题是为什么当我重复运行相同的脚本(通过完整扫描创建、插入更新它自己的统计信息)时,估计的返回行数总是不同的?

Pau*_*ite 7

  1. 执行排序所需的内存量并不像计算输入数据的原始大小那么简单。SQL Server 使用的主要排序算法是归并排序的一种变体,它包括诸如键归一化之类的额外步骤,以确保可以有效地对数据列类型的所有组合进行排序。由于这些额外的步骤,预测在运行时避免溢出所需的内存量并不容易。内存授予是一个估计值。溢出是设计的一部分。在这种边缘情况下,您不应该过分担心小溢出。

  2. SQL Server 2014 包含一个新的基数估计模块,如果上下文数据库的兼容性级别为 120,则使用该模块。您tempdb用于测试,默认情况下为 120 级别。您可以通过更改兼容性级别或使用跟踪标志 9481 来获取 2014 之前的 CE 行为。对于不同的估计行数,除非您使用WITH FULLSCAN带有的选项,否则可能会对统计信息进行采样UPDATE STATISTICS