Mar*_*lli 22 performance sql-server memory execution-plan sort-operator query-performance
我正在努力通过警告Operator usedtempdb最大限度地减少查询计划的排序操作成本to spill data during execution with spill level 2
我在溢出级别 1 的执行期间发现了几篇与溢出数据相关的帖子,但不是级别 2。级别 1 似乎是由过时的统计数据引起的,那么级别 2 呢?我找不到任何与level 2.
我发现这篇与排序警告相关的文章非常有趣:
我的 SQL 服务器?
Microsoft SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64) 2016 年 6 月 17 日 19:14:09 版权所有 (c) Microsoft Corporation Enterprise Edition(64 位),Windows NT 6.3(内部版本 9600:)(管理程序)
我的硬件?
运行以下查询以查找硬件:
-- 来自 SQL Server 2012 的硬件信息
SELECT cpu_count AS [Logical CPU Count], hyperthread_ratio AS [Hyperthread Ratio],
cpu_count/hyperthread_ratio AS [Physical CPU Count],
physical_memory_kb/1024 AS [Physical Memory (MB)], affinity_type_desc,
virtual_machine_type_desc, sqlserver_start_time
FROM sys.dm_os_sys_info WITH (NOLOCK) OPTION (RECOMPILE);
Run Code Online (Sandbox Code Playgroud)
当前分配的内存
SELECT
(physical_memory_in_use_kb/1024) AS Memory_usedby_Sqlserver_MB,
(locked_page_allocations_kb/1024) AS Locked_pages_used_Sqlserver_MB,
(total_virtual_address_space_kb/1024) AS Total_VAS_in_MB,
process_physical_memory_low,
process_virtual_memory_low
FROM sys.dm_os_process_memory;
Run Code Online (Sandbox Code Playgroud)
当我以一年的范围运行查询时,我没有收到任何警告,如下图所示:
但是当我只在 1 天范围内运行它时,我收到此警告on the sort operator:
这是查询:
DECLARE @FromDate SMALLDATETIME = '19-OCT-2016 11:00'
DECLARE @ToDate SMALLDATETIME = '20-OCT-2016 12:00'
SELECT DISTINCT
a.strAccountCode ,
a.strAddressLine6 ,
a.strPostalCode ,
CASE WHEN a.strCountryCode IN ('91','92') THEN 'GB-Int'
ELSE a.strCountryCode
END AS [strCountryCode]
FROM Bocss2.dbo.tblBAccountParticipant AS ap
INNER JOIN Bocss2.dbo.tblBAccountParticipantAddress AS apa ON ap.lngParticipantID = apa.lngParticipantID
AND apa.sintAddressTypeID = 2
INNER JOIN Bocss2.dbo.tblBAccountHolder AS ah ON ap.lngParticipantID = ah.lngParticipantID
INNER JOIN Bocss2.dbo.tblBAddress AS a ON apa.lngAddressID = a.lngAddressID
AND a.blnIsCurrent = 1
INNER JOIN Bocss2.dbo.tblBOrder AS o ON ap.lngParticipantID = o.lngAccountParticipantID
AND o.sdtmOrdCreated >= @FromDate
AND o.sdtmOrdCreated < @ToDate
OPTION(RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
问题:1)在查询计划中我看到了这个:
StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="70"
Run Code Online (Sandbox Code Playgroud)
为什么是 70?我正在使用 sql server 2014
2)我如何摆脱那个排序运算符(如果可能的话)?
3)我已经看到页面预期寿命非常低,除了向该服务器添加更多内存之外,还有什么我可以查看的东西以查看是否可以防止出现此警告?
干杯
在 Shanky 和 Paul White 的回答后更新
我已经根据下面的脚本检查了我的统计数据,它们似乎都是正确的和更新的。
这些是此查询中使用的所有索引和表。
DBCC SHOW_STATISTICS ('dbo.tblBAddress','IDXF_tblBAddress_lngAddressID__INC')
GO
DBCC SHOW_STATISTICS ('dbo.tblBOrder','IX_tblBOrder_sdtmOrdCreated_INCL')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountHolder','PK_tblAccountHolder')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountParticipant','PK_tblBAccountParticipants')
GO
DBCC SHOW_STATISTICS ('dbo.tblBAccountParticipantAddress','IDXF_tblBAccountParticipantAddress_lngParticipantID')
GO
Run Code Online (Sandbox Code Playgroud)
这是我得到的回报:
这是部分结果,但我已经重新访问了所有结果。
对于统计更新,我目前有Ola Hallengren
索引优化作业 - 计划每周运行一次 - 星期日
EXECUTE [dbo].[IndexOptimize]
@Databases = 'USER_DATABASES,-%Archive',
@Indexes = 'ALL_INDEXES' ,
@FragmentationLow = NULL,
@FragmentationMedium = NULL,
@FragmentationHigh = NULL,
@PageCountLevel=1000,
@StatisticsSample =100
,@UpdateStatistics = 'Index',
@OnlyModifiedStatistics = 'Y',
@TimeLimit=10800,
@LogToTable = 'Y'
Run Code Online (Sandbox Code Playgroud)
尽管在运行以下脚本后统计信息似乎已更新,但我没有收到有关排序运算符的更多警告。
UPDATE STATISTICS [Bocss2].[dbo].[tblBOrder] WITH FULLSCAN
--1 hour 04 min 14 sec
UPDATE STATISTICS [Bocss2].[dbo].tblBAddress WITH FULLSCAN
-- 45 min 29 sec
UPDATE STATISTICS [Bocss2].[dbo].tblBAccountHolder WITH FULLSCAN
-- 26 SEC
UPDATE STATISTICS [Bocss2].[dbo].tblBAccountParticipant WITH FULLSCAN
-- 4 min
UPDATE STATISTICS [Bocss2].[dbo].tblBAccountParticipantAddress WITH FULLSCAN
-- 7 min 3 sec
Run Code Online (Sandbox Code Playgroud)
Sha*_*nky 20
2级呢?我找不到与第 2 级相关的任何内容。
根据这个 Old MS Doc,Tempdb 溢出中的数字表示需要对数据进行多少遍才能对数据进行排序。所以 Spill 1 意味着它必须通过 1 次来对数据进行排序,而 2 意味着它必须通过 2 次。
引自博客:
如果涉及排序操作的查询生成溢出级别值为 2 的排序警告事件类,则查询的性能可能会受到影响,因为需要多次遍历数据才能对数据进行排序。在下面的示例中,我们看到溢出级别值为 1,这意味着对数据的一次传递足以完成排序。
为什么是 70?我正在使用 sql server 2014
这是因为图中数据库的兼容级别不是 120(表示 2014 数据库的兼容级别),因为它不是 120 查询将使用旧的基数估计 (CE) 模型处理,称为CardinalityEstimationModelVersion="70"。我相信您知道从 SQL Server 2014 开始,我们有了新的 CE。
我如何摆脱那个排序运算符(如果可能的话)?
您使用的不同命令导致排序操作。正在排序的数据不适合内存,因此它会溢出到 tempdb,当发生这种情况时,执行计划中会给出带有黄色感叹号的排序警告。排序警告并不总是一个问题。
可以在执行计划中看到估计要排序的行数是1,但是在运行时遇到了16353。为排序保留的内存量基于输入的预期(估计)大小,并且在执行期间不能增长(在这种情况下)。
查询的小内存授权 (1632KB) 也在并发执行的内存消耗运算符(排序和“优化”循环连接)之间共享。在您的计划中,这意味着 33.33% (544KB) 可用于在读取行时进行排序(输入内存部分)。这不足以对 16,353 行进行排序,因此它会溢出到tempdb。单级溢出不足以完成排序,因此需要第二级溢出(有关溢出级别的更多详细信息,请参阅末尾的参考资料)。
在 SQL Sentry Plan Explorer 中查看的排序属性
更新统计数据可能有助于解决基数估计问题。您可能会遇到升序键问题,尤其是在 table 上tblBOrder。从该表中简单选择您的问题的文字日期可能会立即估计一行。
我已经看到页面预期寿命非常低,除了向该服务器添加更多内存之外,还有什么我可以查看的内容以查看是否可以防止出现此警告?
PLE 表示 I/O 活动量,它是否增加了?。这是否经常发生或仅在您运行某些查询时发生,或者仅在今天发生。避免膝跳反应,首先我们需要确保您确实面临内存压力或一些产生过多 I/O 的恶意查询导致这种情况。无论如何,您已经为 SQL Server 分配了 97 G 内存。
有关溢出水平和升序关键问题的更多信息,请参阅: