操作员使用 tempdb 在溢出级别 2 的执行期间溢出数据

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 Server 中的排序警告

我的 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)

查询计划在这里

使用 pastetheplan 的查询计划

问题: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 内存。

有关溢出水平和升序关键问题的更多信息,请参阅: