SQL Server 2019 大 INSERT 的性能问题

Ter*_*ski 6 sql-server sql-server-2019

我们正在将多个 ETL 过程从 SQL Server 2016、Windows 2012 服务器转换为 Windows 2019、SQL Server 2019 (CU8) 环境。

一个进程在 SQL Server 2019 中的运行时间比在 SQL Server 2016 中的运行时间长。该进程执行一个INSERT into B, select x from A, wherex是一系列子字符串和 case 语句。

表 A 基本上包含 1 个数据列,6,000 字节长。表 B 由 950 多个数据列组成。我将平面文件中的数据批量插入到表 A 中,然后使用各种子字符串命令将数据解析到表 B 中。

表 A 包含 470 万行并在 47 分钟内加载,为了测试目的我拆分了 100 万行,并在 10 分钟内加载。

在我的 SQL Server 2016、Windows 2012 服务器上,满载运行时间为 12 - 14 分钟,而 100 万次采样运行时间为 1 分 51 秒。

为了咧嘴笑,我在我的 ETL 2019 服务器上停止了 SQL Server 2016 并运行了相同的测试。满载 7 分 14 秒,而 100 万次采样耗时 1 分 32 秒。

所有三个实例的 MAXDOP 均为 8,并行成本阈值 (CTFP) 为 50。

这是运行 SQL Server 2019 以进行 ETL 处理的专用服务器。没有其他应用程序在其上运行:

  • 2 - 3.80Ghz 处理器,每个插槽 4 个内核,每个插槽 8 个逻辑处理器
  • 1571465 MB RAM(1.5 TB)
  • 16,813 GB 板载 SSD 存储
  • 非常受控的测试,测试时没有其他进程在运行

虽然实际的 ETL 过程是基于过程的,但我提取了插入代码,并将其作为 T-SQL 命令在本地服务器上的 SSMS 中运行,以进行测试。

我知道 SQL Server 2019 中有很多新的“性能”改进,我尝试了很多不同的组合(MAXDOP 和 CTFP 的不同组合,打开和关闭不同的 SCOPE 值),到目前为止,没有任何帮助减少运行时间。

一些观察:

  • 将目标表减少到只有 100 列,1 分钟内加载 100 万行;5分钟加载470万
  • 将列数增加到 250 并加载 100 万行需要 6 分钟。
  • 我无法理解它,但是关于 substring/case 函数以及它与 SQL Server 的交互方式的某些东西让我有些难过。
  • 使用不同的 MaxDOP (0,4,8) 和 CTFP 进行多次执行,结果没有差异,除了 MaxDop=4,这会增加运行时间。

代码片段:

INSERT into Base with (TABLOCK)
SELECT 
   CHD_A = substring(importtext,14,28)
  ,CHD_B = getdate()
  ,CHD_C = substring(importtext,14,4)
  ,CHD_D = substring(importtext,18,4)
  ,CHD_E = substring(importtext,22,4)
  ,CHD_F = CASE WHEN substring(importtext,45,6) = ' ' THEN NULL ELSE RTRIM(substring(importtext,45,6)) END  
 , and so on and so on for 950+ columns.
Run Code Online (Sandbox Code Playgroud)

PS 在运行 SQL Server 2017 的 VM 服务器上对相同负载进行了快速测试,内存为 16GB。查询在 1 分 19 秒内完成,100 万行。

因此,我正在向 SQL Server 2019 专家寻求建议,以及在哪里查看、调整什么。此时无法转换为 SSIS。

这是计划;

SQL 2016

SQL 2017

SQL 2019

小智 1

来自评论:

就所有意图和目的而言,这些计划都是相同的。因此,我会更多地关注物理设置和服务器设置的差异。如果 2016 年和 2019 年的查询优化器达到相同的计划,但行为不同,那么追逐优化器设置、查询提示、统计信息、基数估计和其他计划驱动的决策就是浪费时间。由于大部分性能差异在于聚集索引扫描(1 秒与 28 秒),因此很可能是磁盘或内存问题。虽然实际的插入操作也长了一倍。同样可能的问题。——格兰特·弗里奇