排序溢出到 tempdb 但估计行等于实际行

Fre*_*gen 15 sql-server tempdb sorting sql-server-2016 cardinality-estimates

在最大内存设置为 25GB 的 SQL Server 2016 SP2 上,我们有一分钟执行大约 80 次的查询。该查询将大约 4000 页溢出到 tempdb。这会导致 tempdb 的磁盘上出现大量 IO。

当您查看查询计划(简化查询)时,您会看到估计行数等于实际行数,但仍然会发生溢出。所以过时的统计数据不能成为问题的原因。

我做了一些测试和以下查询溢出到 Tempdb:

select id --uniqueidentifier
from SortProblem
where [status] ='A'
order by SequenceNumber asc
option (maxdop 1)
Run Code Online (Sandbox Code Playgroud)

但是,如果我选择不同的列,则不会发生溢出:

select startdate --datetime
from SortProblem
where [status] ='A'
order by SequenceNumber asc 
option (maxdop 1)
Run Code Online (Sandbox Code Playgroud)

所以我试图“放大” id 列的大小:

select CONVERT(nvarchar(512),id)
from SortProblem
where [status] ='A'
order by SequenceNumber asc 
option (maxdop 1)
Run Code Online (Sandbox Code Playgroud)

然后也不会发生溢出。

为什么 uniqueidentifier 不会溢出到 tempdb 和 datatime 列?当我删除大约 20000 条记录时,当我选择 id 列时也不会发生溢出。

使用以下脚本,您可以重现该问题:

CREATE TABLE SortProblem
  (
     id             UNIQUEIDENTIFIER,
     startdate      DATETIME,
     sequencenumber BIGINT,
     status         VARCHAR(50),
     PRIMARY KEY CLUSTERED(id)
  )

SET nocount ON;

WITH nums(num)
     AS (SELECT TOP 103000 ROW_NUMBER()
                             OVER (
                               ORDER BY 1/0)
         FROM   sys.all_objects o1,
                sys.all_objects o2)
INSERT INTO SortProblem
SELECT newid(),
       DATEADD(millisecond, num, GETDATE()),
       num,
       CASE
         WHEN num <= 100000 THEN 'A'
         WHEN num <= 101000 THEN 'B'
         WHEN num <= 102000 THEN 'C'
         WHEN num <= 103000 THEN 'D'
       END
FROM   nums

CREATE NONCLUSTERED INDEX [IX_Status]
  ON [dbo].[SortProblem]([status] ASC)
  INCLUDE ([sequencenumber]) 
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 14

启用跟踪标志 7470。

修复:当估计的行数和行大小正确时,排序运算符会溢出到 SQL Server 2012 或 SQL Server 2014 中的 tempdb

正如我在回答查询计划问题时所写:

该跟踪标志纠正了计算中的疏忽。它使用起来非常安全,在我看来应该默认开启。更改受跟踪标志保护,只是为了避免意外的计划更改。