Sql server 为什么我在两台服务器之间得到不同的实际执行计划?
我有一个在生产和开发环境中运行的SQL Server查询。完全相同的查询Sql server 为什么我在两台服务器之间得到不同的实际执行计划?,sql-server,tsql,sql-server-2017,Sql Server,Tsql,Sql Server 2017,我有一个在生产和开发环境中运行的SQL Server查询。完全相同的查询 SELECT DISTINCT [Record_Transformation_ACCRUALS], [Record_Transformation_FA:AMORTIZATION], [Record_Transformation_BONUS:AMORTIZATION], [Record_Transformation_CPH:BYLABOUR], [Record_Transfor
SELECT DISTINCT
[Record_Transformation_ACCRUALS],
[Record_Transformation_FA:AMORTIZATION],
[Record_Transformation_BONUS:AMORTIZATION],
[Record_Transformation_CPH:BYLABOUR],
[Record_Transformation_CPH:BYTARGETHOURS],
[Record_Transformation_OVERHEAD:CULTURE],
[Record_Transformation_DEDICATED COSTCENTER],
[Record_Transformation_PUSHDOWN:EXPENSE],
[Record_Transformation_OVERHEAD:FACILITIES],
[Record_Transformation_OVERHEAD:GENOME],
[Record_Transformation_TAXES:MANAGEMENT],
[Record_Transformation_TAXES:MARKETING],
[Record_Transformation_OVERHEAD:OFFICETECH],
[Record_Transformation_EXPENSE:PASSTHROUGH],
[Record_Transformation_OVERHEAD:PEOPLEPRACTICES],
[Record_Transformation_OVERHEAD:RECRUITING],
[Record_Transformation_TAXES:SALES],
[Record_Transformation_Static Transfer],
[Record_Label]
FROM
Warehouse_20181204
WHERE
Is_Target_Employee = 1 OR Is_Source_Employee = 1
我们比较了这两个表的创建脚本,它们是相同的(除了有问题的表的名称)
我们还验证了它们都使用了聚集列存储索引
在开发过程中,此查询只需不到一秒钟的时间。按prod大约需要一分钟。我们起初认为数据的大小可能是问题所在,但是差异很小(几十万行)
然后,我们检查了这两个项目的实际执行计划。在dev上,实际执行计划为:
在prod上,实际执行计划非常不同,尽管:
我们发现自己很难理解为什么会这样。我们已验证SQL Server的版本相同:
Microsoft SQL Server 2017 (RTM-CU5) (KB4092643) - 14.0.3023.8 (X64)
Web Edition (64-bit) on Windows Server 2016 Datacenter 10.0 <X64> (Build 14393:) (Hypervisor)
Microsoft SQL Server 2017(RTM-CU5)(KB4092643)-14.0.3023.8(X64)
Windows Server 2016数据中心10.0(版本14393:)上的Web版(64位)(虚拟机监控程序)
我的问题有两个方面:
- 两台服务器都有8G内存,可用内存都超过1G
- 两台服务器都有2个处理器
- 硬件与您得到的完全相同-两个aws实例大小相同
- 我们已经验证了两个表和集群列存储索引的sql是相同的
DISTINCT使您的查询成为这方面的简写:
SELECT
[Record_Transformation_ACCRUALS],
[Record_Transformation_FA:AMORTIZATION],
[Record_Transformation_BONUS:AMORTIZATION],
[Record_Transformation_CPH:BYLABOUR],
[Record_Transformation_CPH:BYTARGETHOURS],
[Record_Transformation_OVERHEAD:CULTURE],
[Record_Transformation_DEDICATED COSTCENTER],
[Record_Transformation_PUSHDOWN:EXPENSE],
[Record_Transformation_OVERHEAD:FACILITIES],
[Record_Transformation_OVERHEAD:GENOME],
[Record_Transformation_TAXES:MANAGEMENT],
[Record_Transformation_TAXES:MARKETING],
[Record_Transformation_OVERHEAD:OFFICETECH],
[Record_Transformation_EXPENSE:PASSTHROUGH],
[Record_Transformation_OVERHEAD:PEOPLEPRACTICES],
[Record_Transformation_OVERHEAD:RECRUITING],
[Record_Transformation_TAXES:SALES],
[Record_Transformation_Static Transfer],
[Record_Label]
FROM Warehouse_20181204
WHERE Is_Target_Employee = 1 OR Is_Source_Employee = 1
GROUP BY
[Record_Transformation_ACCRUALS],
[Record_Transformation_FA:AMORTIZATION],
[Record_Transformation_BONUS:AMORTIZATION],
[Record_Transformation_CPH:BYLABOUR],
[Record_Transformation_CPH:BYTARGETHOURS],
[Record_Transformation_OVERHEAD:CULTURE],
[Record_Transformation_DEDICATED COSTCENTER],
[Record_Transformation_PUSHDOWN:EXPENSE],
[Record_Transformation_OVERHEAD:FACILITIES],
[Record_Transformation_OVERHEAD:GENOME],
[Record_Transformation_TAXES:MANAGEMENT],
[Record_Transformation_TAXES:MARKETING],
[Record_Transformation_OVERHEAD:OFFICETECH],
[Record_Transformation_EXPENSE:PASSTHROUGH],
[Record_Transformation_OVERHEAD:PEOPLEPRACTICES],
[Record_Transformation_OVERHEAD:RECRUITING],
[Record_Transformation_TAXES:SALES],
[Record_Transformation_Static Transfer],
[Record_Label]
优化器尝试满足这类查询的两种最常见的方法。首先,它过滤您的列存储索引,以查找是\u Target\u Employee=1还是\u Source\u Employee=1
;这就是你计划中的过滤器显示的内容。接下来,要通过(或区分)处理组,它将:
流聚合器
返回一个不同的集合(如产品执行计划所示)
或OPTION (QUERYTRACEON 8649);
这将迫使优化器运行并行计划。如果没有并行计划,则会出现另一个问题(可能Prod中的MAXDOP设置设置为1)。如果您确实得到了一个并行计划,并且它提高了性能,那么您已经确定了问题(您需要一个并行计划)。如果并行计划不能解决问题,那么您可能需要考虑该表中包含查询中的所有列的非聚集、筛选的CysNoStand索引,然后用进行筛选。
WHERE Is_Target_Employee = 1 OR Is_Source_Employee = 1
你现在正在做一个大扫描,读取大量不需要读取的行
发回任何问题
于2018年6月12日更新:
很抱歉更新太晚,出现了很多工作内容
我仔细研究了一下执行计划,发现了一些有趣的事情。在阅读@Martin_Smith发布的内容之前,我拍摄了以下截图:
我百分之百同意串行与并行执行计划在这里不是问题,但是,在产品计划的情况下,串行运行会使糟糕的执行计划变得更慢。正如Martin所解释的,问题在于哈希匹配计划是一个更好的计划
两个计划都从列存储索引(Dev中为5M,Prod中为6M)中检索相似数量的行。在每个计划中,所有行都将被过滤,但在Prod计划中,所有行都将由排序运算符vs使用其哈希聚合再次处理
不管你投入多少CPU:对630万行进行19列排序会很慢,特别是对于串行计划。在我看来,并行性的最佳用途之一是处理这样的大型排序。这就是说,不应该需要某种类型的。我以前在哪里见过,当优化器可以使用排序(如在Prod计划中)或散列(如在Dev计划中)解决查询时,它将在强制执行并行执行计划时使用散列选择该计划。我怀疑在您的情况下,强制执行并行计划会导致优化器选择使用散列的计划
最后-我之前忘了提到这一点,不要在Prod中使用
选项(QUERYTRACEON 8649)
;这是无证的。我用它来测试。在prod使用中,串行与并行并不是一个真正的问题,因为您的最大并行度仅为2
导致查询速度缓慢的原因是内存不足和大量排序溢出(达到8级)
您的查询返回305
行,但SQL Server在一个计划中估计2561980
,在另一个计划中估计3709060
对于305行,您需要一个散列聚合,因为它只需要305个不同分组值的内存,而不需要整个600万行的内存以及排序所使用的额外开销
即使在使用散列聚合的计划中,对输出行数的高估也意味着您将收到一个过量内存授予警告
查询内存授予检测到“过度授予”,这可能会影响
可靠性。
CREATE STATISTICS SomeName ON Warehouse_20181204 (
[Record_Transformation_ACCRUALS],
[Record_Transformation_FA:AMORTIZATION],
[Record_Transformation_BONUS:AMORTIZATION],
[Record_Transformation_CPH:BYLABOUR],
[Record_Transformation_CPH:BYTARGETHOURS],
[Record_Transformation_OVERHEAD:CULTURE],
[Record_Transformation_DEDICATED COSTCENTER],
[Record_Transformation_PUSHDOWN:EXPENSE],
[Record_Transformation_OVERHEAD:FACILITIES],
[Record_Transformation_OVERHEAD:GENOME],
[Record_Transformation_TAXES:MANAGEMENT],
[Record_Transformation_TAXES:MARKETING],
[Record_Transformation_OVERHEAD:OFFICETECH],
[Record_Transformation_EXPENSE:PASSTHROUGH],
[Record_Transformation_OVERHEAD:PEOPLEPRACTICES],
[Record_Transformation_OVERHEAD:RECRUITING],
[Record_Transformation_TAXES:SALES],
[Record_Transformation_Static Transfer],
[Record_Label] ) WITH FULLSCAN