最大メモリが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])
トレースフラグ7470を有効にします。
FIX:SQL Server 2012またはSQL Server 2014で、行の推定数と行サイズが正しい場合、並べ替え演算子がtempdbに流出します
クエリプランの質問 への回答で私が書いたように:
このトレースフラグは、計算の見落としを修正します。それは使用することは非常に安全であり、私の意見ではデフォルトでオンにすべきです。予期しない計画の変更を回避するために、変更はトレースフラグによって保護されています。