操作员在执行溢出级别2的过程中使用tempdb溢出数据


17

我正在努力通过警告Operator usedtempdb 将查询计划上的排序操作的成本降至最低to spill data during execution with spill level 2

我发现有几个与泄漏级别为1的执行过程中的泄漏数据有关的帖子,但与级别2无关,而级别1似乎是由于过时的统计信息引起的,级别2呢?我找不到与关联的任何内容level 2

我发现本文与排序警告有关非常有趣:

永不忽略SQL Server中的排序警告

我的SQL Server?

Microsoft SQL Server 2014(SP2)(KB3171021)-12.0.5000.0(X64)2016年6月17日19:14:09版权所有(c)Windows NT 6.3(Build 9600:)上的Microsoft Corporation Enterprise Edition(64位)(系统管理程序)

我的硬件?

运行下面的查询以查找硬件:

-来自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);

在此处输入图片说明

当前分配的内存

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;

在此处输入图片说明

当我在一年范围内运行查询时,没有收到任何警告,如下图所示:

在此处输入图片说明

但是当我仅将其运行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)

查询计划在这里

使用粘贴计划查询计划

问题:1)在查询计划中,我看到以下内容:

StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="70" 

为什么是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

这是我得到的回报:

在此处输入图片说明

在此处输入图片说明

这是部分结果,但我已重新访问了所有结果。

为了统计更新,我目前有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'

尽管统计信息似乎已更新,但是在运行以下脚本后,我再也没有收到有关排序运算符的警告。

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

查询时间减少了多少?
进水

我永远无法实现一个解决方案,使我能够在如此大的表上保持统计数据的更新。解决的办法是对表进行分区并使用增量统计,但是我从来没有下来实现它,因为我离开了那个雇主。我很想实现的东西。
Marcello Miorelli'7

Answers:


17

那2级呢?我找不到与第2级相关的任何内容。

根据此旧MS Doc,Tempdb溢出中的数字表示需要对数据进行多少遍才能对数据进行排序。因此,溢出1表示必须通过1次才能对数据进行排序,而溢出2则意味着必须通过2次。

从博客引用:

如果涉及排序操作的查询生成溢出级别值为2的“排序警告”事件类,则该查询的性能可能会受到影响,因为需要多次遍历数据才能对数据进行排序。在下面的示例中,我们看到溢出级别值为1,这意味着一次通过数据就足以完成排序。

为什么是70?我正在使用SQL Server 2014

这是因为图片中数据库的兼容性级别不是120(表示2014数据库的兼容性级别),因为不是120,将使用称为的旧基数估计(CE)模型处理查询CardinalityEstimationModelVersion="70"。我确定您知道从SQL Server 2014开始,我们有了新的CE。

我如何摆脱那种排序运算符(如果可能的话)?

您正在使用的独特命令导致排序操作。正在排序的数据无法放入内存,因此会溢出到tempdb,并且在发生这种情况时,在执行计划中会给出带有黄色感叹号的排序警告。排序警告并不总是一个问题。

您可以在执行计划中看到要排序的估计行数为1,但是在运行时遇到了16,353。保留用于排序的内存量基于输入的预期(估计)大小,并且在执行期间不会增长(在这种情况下)。

查询的少量内存授权(1632KB)也可以在同时执行的内存消耗运算符(排序和“优化”循环联接)之间共享。在您的计划中,这意味着33.33%(544KB)可用于在读取行时进行排序(输入存储分数)。该内存不足,无法对16,353行进行排序,因此溢出到tempdb。单级泄漏不足以完成分类,因此需要第二级泄漏(有关泄漏级别的更多详细信息,请参阅最后的参考)。

排序属性

按SQL Sentry Plan Explorer中的顺序对属性进行排序

更新统计信息可能会有助于解决基数估计问题。您可能正在遇到升序的关键问题,尤其是在table上tblBOrder。从该表中选择一个带有您问题的字面日期的简单选择,现在可能会估计一行。

我已经看到页面寿命期望值很低,除了向该服务器添加更多的内存之外,还有什么我可以看看的,看看是否可以防止此警告?

PLE表示I / O活动的数量,它增加了吗?因此,通常还是仅在您运行某些查询时才发生这种情况,或者只是在今天才发生这种情况。避免膝盖跳动反应,首先,我们需要确保您确实面临内存压力,或者某些流氓查询导致了太多的I / O导致这种情况。无论如何,您已经为SQL Server分配了97 G内存。

有关泄漏水平和上升关键问题的更多信息,请参见:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.