web-dev-qa-db-ja.com

スピルをtempdbにソートしますが、推定行は実際の行と同じです

最大メモリが25GBに設定されたSQL Server 2016 SP2では、1分間に約80回実行されるクエリがあります。クエリは、約4000ページをtempdbにスピルします。これにより、tempdbのディスクでIOが大量に発生します。

クエリプラン (シミュレートされたクエリ)を見ると、推定行の数が実際の行の数と同じであるにもかかわらず、スピルが発生していることがわかります。したがって、古い統計が問題の原因になることはありません。

Tempdbにいくつかのテストを実行し、クエリの流出を追跡しました。

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

しかし、別の列を選択した場合、流出は発生しません。

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

だから私はid列のサイズを「拡大」しようとしました:

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

その後もこぼれは発生しません。

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]) 
15

トレースフラグ7470を有効にします。

FIX:SQL Server 2012またはSQL Server 2014で、行の推定数と行サイズが正しい場合、並べ替え演算子がtempdbに流出します

クエリプランの質問 への回答で私が書いたように:

このトレースフラグは、計算の見落としを修正します。それは使用することは非常に安全であり、私の意見ではデフォルトでオンにすべきです。予期しない計画の変更を回避するために、変更はトレースフラグによって保護されています。

14
Paul White 9