UAT和PROD服务器上执行计划的差异


39

我想了解为什么在UAT(运行3秒)与PROD(运行23秒)中执行相同查询会有如此大的差异。

UAT和PROD都具有准确的数据和索引。

查询:

set statistics io on;
set statistics time on;

SELECT CONF_NO,
       'DE',
       'Duplicate Email Address ''' + RTRIM(EMAIL_ADDRESS) + ''' in Maintenance',
       CONF_TARGET_NO
FROM   CONF_TARGET ct
WHERE  CONF_NO = 161
       AND LEFT(INTERNET_USER_ID, 6) != 'ICONF-'
       AND ( ( REGISTRATION_TYPE = 'I'
               AND (SELECT COUNT(1)
                    FROM   PORTFOLIO
                    WHERE  EMAIL_ADDRESS = ct.EMAIL_ADDRESS
                           AND DEACTIVATED_YN = 'N') > 1 )
              OR ( REGISTRATION_TYPE = 'K'
                   AND (SELECT COUNT(1)
                        FROM   CAPITAL_MARKET
                        WHERE  EMAIL_ADDRESS = ct.EMAIL_ADDRESS
                               AND DEACTIVATED_YN = 'N') > 1 ) ) 

在UAT上:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 11 ms, elapsed time = 11 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(3 row(s) affected)
Table 'Worktable'. Scan count 256, logical reads 1304616, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PORTFOLIO'. Scan count 1, logical reads 84761, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 2418 ms,  elapsed time = 2442 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

在此处输入图片说明

在PROD上:

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(3 row(s) affected)
Table 'PORTFOLIO'. Scan count 256, logical reads 21698816, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CAPITAL_MARKET'. Scan count 256, logical reads 9472, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'CONF_TARGET'. Scan count 1, logical reads 100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 23937 ms,  elapsed time = 23935 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

在此处输入图片说明

请注意,在PROD上,查询建议缺少索引,并且正如我所测试的那样,这是有益的,但这不是讨论的重点。

我只是想了解一下:在UAT上-为什么sql server创建工作表,而在PROD上却没有呢?它在UAT而非PROD上创建表假脱机。另外,为什么UAT与PROD的执行时间如此不同?

注意 :

我在两台服务器上都运行sql server 2008 R2 RTM(很快将使用最新的SP进行修补)。

UAT:最大内存8GB。MaxDop,处理器关联和最大工作线程为0。

Logical to Physical Processor Map:
*-------  Physical Processor 0
-*------  Physical Processor 1
--*-----  Physical Processor 2
---*----  Physical Processor 3
----*---  Physical Processor 4
-----*--  Physical Processor 5
------*-  Physical Processor 6
-------*  Physical Processor 7

Logical Processor to Socket Map:
****----  Socket 0
----****  Socket 1

Logical Processor to NUMA Node Map:
********  NUMA Node 0

PROD:最大内存60GB。MaxDop,处理器关联和最大工作线程为0。

Logical to Physical Processor Map:
**--------------  Physical Processor 0 (Hyperthreaded)
--**------------  Physical Processor 1 (Hyperthreaded)
----**----------  Physical Processor 2 (Hyperthreaded)
------**--------  Physical Processor 3 (Hyperthreaded)
--------**------  Physical Processor 4 (Hyperthreaded)
----------**----  Physical Processor 5 (Hyperthreaded)
------------**--  Physical Processor 6 (Hyperthreaded)
--------------**  Physical Processor 7 (Hyperthreaded)

Logical Processor to Socket Map:
********--------  Socket 0
--------********  Socket 1

Logical Processor to NUMA Node Map:
********--------  NUMA Node 0
--------********  NUMA Node 1

更新:

UAT执行计划XML:

http://pastebin.com/z0PWvw8m

PROD执行计划XML:

http://pastebin.com/GWTY16YY

UAT执行计划XML-通过PROD生成计划:

http://pastebin.com/74u3Ntr0

服务器配置:

产品:PowerEdge R720xd-英特尔®至强®CPU E5-2637 v2 @ 3.50GHz。

UAT:PowerEdge 2950-Intel(R)Xeon(R)CPU X5460 @ 3.16GHz

我已经张贴在answer.sqlperformance.com


更新:

感谢@swasheck的建议

将PROD上的最大内存从60GB更改为7680 MB,我能够在PROD中生成相同的计划。查询与UAT同时完成。

现在我需要了解-为什么?而且,由此,我将无法证明这个怪物服务器取代旧服务器!

Answers:


43

缓冲池的潜在大小会以多种方式影响查询优化器的计划选择。据我所知,超线程不会影响计划的选择(尽管潜在可用调度程序的数量当然可以)。

工作空间记忆

对于包含诸如排序和散列之类的消耗内存的迭代器的计划,缓冲池的大小(除其他事项外)决定了运行时查询可使用的最大内存授权量。

在SQL Server 2012(所有版本)中,此数字记录在查询计划的根节点上的Optimizer Hardware Dependencies部分中,显示为Estimated Available Memory Grant。2012年之前的版本不会在展会计划中报告此数字。

估计的可用内存授权是查询优化器使用的成本模型的输入。结果,与具有较低设置的计算机相比,在具有较大缓冲池设置的计算机上更有可能选择需要较大排序或哈希运算的计划替代方案。对于具有安装非常大量的内存,成本模型可以走得太远用这种思维-具有非常大的排序或哈希值选择方案,其中一种替代策略是最好(KB2413549 -采用大容量的内存可以导致SQL Server中效率低下的计划-TF2335)。

工作空间内存的授予不是您所要考虑的因素,但是这是值得了解的。

资料存取

缓冲池的潜在大小也会影响优化器的数据访问成本模型。该模型中的一个假设是,每个查询都以冷缓存开始-因此,假定对页面的首次访问会导致物理I / O。该模型确实尝试考虑了重复访问将来自缓存的机会,该因素尤其取决于缓冲池的潜在大小。

问题中显示的查询计划中的聚簇索引扫描是重复访问的一个示例。对于嵌套循环半连接的每次迭代,重新扫描(重复,不更改相关参数)。半联接的外部输入估计28.7874行,这些扫描的查询计划属性显示结果估计为27.7874倒带。

同样,仅在SQL Server 2012中,计划的根迭代器Estimated Pages CachedOptimizer Hardware Dependencies部分中显示的编号。该数字报告了成本核算算法的输入之一,该成本核算算法考虑了来自缓存的重复页面访问的机会。

这样做的结果是,与最大缓冲池较小的安装相比,配置的最大缓冲池较大的安装将倾向于减少读取(或搜索)读取相同页面一次以上的成本。

在简单的计划中,通过(estimated number of executions) * (estimated CPU + estimated I/O)与估计的运营商成本进行比较,可以看到回绕扫描的成本降低,而成本更低。由于半联接和联合的影响,示例计划中的计算更加复杂。

但是,问题中的计划似乎显示了这样一种情况,即在重复扫描和创建临时索引之间的选择非常均衡。在具有更大缓冲池的计算机上,重复扫描的成本比创建索引要低一些。在缓冲池较小的计算机上,扫描成本减少了较小的数量,这意味着索引假脱机计划对于优化器而言似乎稍微便宜一些。

计划选择

优化器的成本模型有许多假设,并包含大量详细的计算。并非总是(甚至通常)可能会遵循所有细节,因为并非我们需要的所有数字都已公开,并且算法可以在发行版之间进行更改。尤其是,用于考虑遇到缓存页面的机会的缩放公式不是众所周知的。

更重要的是,在这种情况下,优化器的计划选择始终基于错误的数字。从聚簇索引查找中估计的行数为28.7874,而在运行时遇到256行-几乎超出了一个数量级。我们无法直接看到优化器具有的有关那些28.7874行中的值的预期分布的信息,但它也很可能也是错误的。

当估计错误时,计划选择和运行时性能基本上不会比偶然好。带有索引假脱机的计划碰巧比重复扫描执行得更好,但是认为增加缓冲池的大小是异常的原因是完全错误的。

如果优化器具有正确的信息,则生成一个不错的执行计划的机会就大得多。具有更多内存的实例通常在工作负载上的性能要优于具有更少内存的另一个实例,但是并不能保证,尤其是在基于错误数据选择计划时。

这两个实例都以自己的方式建议缺少索引。一个报告了显式丢失的索引,另一个报告了具有相同特征的索引假脱机。如果索引提供了良好的性能和计划稳定性,那就足够了。我的倾向是也重写查询,但这可能是另一回事了。


18

Paul White非常清楚地解释了背后的原因-在具有更多内存的服务器上运行时sql服务器的行为。

另外,非常感谢@swasheck首次发现问题。

与微软一起开了一个案子,下面是建议。

通过使用跟踪标志T2335作为启动参数来解决此问题。

KB2413549 -采用大容量的内存可以导致低效计划在SQL Server中介绍了它的更多细节。

此跟踪标志将导致SQL Server在执行查询时生成一个在内存消耗方面更为保守的计划。它不限制SQL Server可以使用多少内存。为SQL Server配置的内存仍将由数据缓存,查询执行和其他使用者使用。在将其应用于生产环境之前,请确保您彻底测试了此选项。


13

最大内存设置和超线程都会影响计划的选择。

此外,我注意到您的“设置”选项在每种环境中都不同:

UAT上的StatementSetOptions:

ANSI_NULLS="true" 
ANSI_PADDING="true" 
ANSI_WARNINGS="true" 
ARITHABORT="true" 
CONCAT_NULL_YIELDS_NULL="true" 
NUMERIC_ROUNDABORT="false" 
QUOTED_IDENTIFIER="true" 

产品上的StatementSetOptions:

ANSI_NULLS="true" 
ANSI_PADDING="true" 
ANSI_WARNINGS="true" 
ARITHABORT="false" 
CONCAT_NULL_YIELDS_NULL="true"
NUMERIC_ROUNDABORT="false"
QUOTED_IDENTIFIER="true" 

SQL可以基于SET选项生成不同的计划。如果您从不同的SSMS会话或从应用程序的不同执行中捕获计划,则经常会发生这种情况。

确保开发人员使用一致的连接字符串。


2
您正确地说最大内存和超线程可能会影响计划缓存,但我想详细了解发生这种情况的原因和原因。感谢您的回答。
Kin Shah 2013年

2
正如Amanda所说,如果SET选项在ARITHABORT中有所不同,也许您应该看看dba.stackexchange.com/questions/9840/…–
ARA
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.