これはSQL Serverのバグです(2008年から2014年まで)。
私のバグレポートはこちらです。
フィルター条件は、残留述部としてスキャン演算子にプッシュダウンされますが、ソートに許可されたメモリーは、事前フィルターのカーディナリティー推定値に基づいて誤って計算されます。
この問題を説明するために、(文書化されておらず、サポートされていない)トレースフラグ9130を使用して、フィルターがスキャン演算子にプッシュダウンされるのを防ぎます。ソートに許可されるメモリは、スキャンではなく、フィルター出力の推定カーディナリティに基づいて正しくなりました。
SELECT
T.TID,
T.FilterMe,
T.SortMe,
T.Unused
FROM dbo.Test AS T
WHERE
T.FilterMe = 567
ORDER BY
T.SortMe
OPTION (QUERYTRACEON 9130); -- Not for production systems!
以下のための生産システム、ステップは、と解釈する必要が回避問題の平面形状(別の列にソートしてスキャンに押し込まフィルタ)。これを行う1つの方法は、フィルター条件のインデックスを提供すること、および/または必要な並べ替え順序を提供することです。
-- Index on the filter condition only
CREATE NONCLUSTERED INDEX IX_dbo_Test_FilterMe
ON dbo.Test (FilterMe);
このインデックスを配置すると、ソートに必要なメモリ許可は928KBのみになります。
さらに進むと、次のインデックスはソートを完全に回避できます(ゼロメモリ許可)。
-- Provides filtering and sort order
-- nvarchar(max) column deliberately not INCLUDEd
CREATE NONCLUSTERED INDEX IX_dbo_Test_FilterMe_SortMe
ON dbo.Test (FilterMe, SortMe);
SQL Server x64 Developer Editionの次のビルドでテストおよびバグ確認:
2014 : 12.00.2430 (RTM CU4)
2012 : 11.00.5556 (SP2 CU3)
2008R2 : 10.50.6000 (SP3)
2008 : 10.00.6000 (SP4)
これは、SQL Server 2016 Service Pack 1で修正されました。リリースノートには以下が含まれます。
VSTSバグ番号8024987
プッシュダウン述語を使用したテーブルスキャンとインデックススキャンは、親演算子のメモリ許可を過大評価する傾向があります。
修正済みのテストおよび確認済み:
Microsoft SQL Server 2016 (SP1) - 13.0.4001.0 (X64) Developer Edition
Microsoft SQL Server 2014 (SP2-CU3) 12.0.5538.0 (X64) Developer Edition
両方のCEモデル。