sql-server – 过多的排序内存授予
为什么这个简单的查询被授予如此多的内存?
-- Demo table CREATE TABLE dbo.Test ( TID integer IDENTITY NOT NULL,FilterMe integer NOT NULL,SortMe integer NOT NULL,Unused nvarchar(max) NULL,CONSTRAINT PK_dbo_Test_TID PRIMARY KEY CLUSTERED (TID) ); GO -- 100,000 example rows INSERT dbo.Test WITH (TABLOCKX) (FilterMe,SortMe) SELECT TOP (100 * 1000) CHECKSUM(NEWID()) % 1000,CHECKSUM(NEWID()) FROM sys.all_columns AS AC1 CROSS JOIN sys.all_columns AS AC2; GO -- Query SELECT T.TID,T.FilterMe,T.SortMe,T.Unused FROM dbo.Test AS T WHERE T.FilterMe = 567 ORDER BY T.SortMe; 估计50行,优化器保留近500 MB的排序: 解决方法这是SQL Server中的一个错误(从2008年到2014年).我的错误报告是here. 过滤条件作为残差谓词被下推到扫描操作符中,但是基于预过滤器基数估计错误地计算为该排序授予的存储器. 为了说明问题,我们可以使用(未??记录和不支持的)跟踪标志9130来防止过滤器被压入扫描操作符.授予排序的内存现在正确地基于Filter输出的估计基数,而不是扫描: SELECT T.TID,T.Unused FROM dbo.Test AS T WHERE T.FilterMe = 567 ORDER BY T.SortMe OPTION (QUERYTRACEON 9130); -- Not for production systems! 对于生产系统,需要采取措施以避免有问题的计划形状(将过滤器推入扫描并在另一列上进行排序).一种方法是提供过滤条件的索引和/或提供所需的排序顺序. -- 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修复.发行说明包括以下内容:
经测试并确认固定于: > Microsoft SQL Server 2016(SP1) – 13.0.4001.0(X64)开发人员版 两种CE型号. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |