我有一个存储过程,它将三个大表连接在一起(每个大约 2000 万条记录)并将记录加载到一个临时表中。然后将临时表中的数据合并到一个包含大约 6000 万条记录的现有表中。
服务器离线并显示以下错误消息:
由于内存压力,AppDomain 2 (SSISDB.dbo.[runtime].1] 被标记为卸载。
让服务器重新联机后,我重新启动 SQL 服务以清除任何可能一直存在的进程。再次开始工作,并且没有问题地完成。
我正在运行具有 128GB RAM 的 SQL Server 2019。64 位虚拟服务器上的最大服务器内存为 117964MB。有人在任务管理器中告诉我内存使用率为 94%,这可能是问题所在。但是 SQL 不会占用所有可用内存并保留它吗?所以看起来它正在按预期运行。
sp_WhoIsActive
揭示了一些状态为“暂停”和“等待命令”的查询,但我认为这些不会产生太大影响。128GB 的内存似乎足够了,但我想这与它被要求做的工作有关。知道如何排除故障或防止再次发生吗?
服务器的数据驱动器约为 1.6TB。连接中的两个较大的数据库是 10GB 的 1900 万行和 13GB 的 2000 万行。这些进入一个临时表,然后MERGE
进入一个有 5300 万行的 26GB 表。
请求的内存授权为 45GB,实际为 30GB。这项工作是在正常工作时间之外进行的,所以应该没有竞争性查询,但我不能 100% 确认有人没有工作到很晚。
我确实注意到它也必须这样做CONVERT_IMPLICIT
。这对所需的内存有重大影响吗?
查询计划链接: https ://www.brentozar.com/pastetheplan/?id=SyXaty7xK
关于您的服务器
尽管授予了 29 GB 内存,但此查询在两个地方严重溢出。这是关于最大服务器内存设置为 115 GB 的系统上查询可以要求的高端内容。
授予该大小的内存的原因是优化器估计它将需要对 46 GB 的数据进行排序:
您可以通过查看资源调控器来查看内存授予百分比的详细信息——单个查询可以请求最大服务器内存设置的 25% 左右——并且最多三个查询可以同时请求完全授予。
如果您获得了该大小的授权,但仍会看到如此数量的溢出和时间消耗,这可能意味着您的服务器就内存而言远远低于配置。
由于两个运算符都在批处理模式下执行,因此您看到的时间是per operator。
我敢肯定,如果您查看此服务器的等待统计信息(考虑到 1.6 TB 的数据),
PAGEIOLATCH_
可能会出现这种情况,SLEEP_TASK
或者IO_COMPLETION
这种大小的溢出很常见。虽然这两种等待也可以与其他事情相关联,但我经常看到它们在像你这样的情况下堆积起来。我首先建议为您的服务器添加更实际的内存量。我不知道这个数字是多少(我也不能在这里告诉你),但我可能会根据数据大小而不是其他目标来瞄准 512 GB 或更高。如果还没有,您还应该打开内存中的锁定页面。
关于您的查询
我看不到全文,因为查询计划中出现的只是插入和选择列表的一部分,但鉴于看起来我可以对整体代码质量做出一些合理的假设。
例如,有几个连接在表达式上,这可能表明您正在将连接列包装在类似
rtrim
或之类的函数中isnull
。但是您的主要问题是在查询的末尾和上图所示的溢出。
让我们谈谈那些!
哈希连接
哈希联接用于
DISTINCT
您在143 列查询中抛出的问题。这让我毛骨悚然,写这篇文章的人如果要继续使用 SQL Server,应该强烈考虑接受一些培训。我建议找到产生唯一行的列的较小组合,并使用row_number来标记它们,就像我在这个视频中展示的那样:
一个伪代码示例如下所示:
只需确保您的索引适合支持窗口功能。
种类
排序在那里,因为您的
#temp
表上有一个聚集索引。如果您将表创建为堆,并稍后添加索引,则可以避免查询运行时的不愉快,但根据各种本地因素,添加索引可能并不有趣。
如果可能的话,我还建议在您的插入
tablock
中添加一个提示以鼓励完全并行插入。现在,您的查询在插入之前是单线程的,这肯定会损害此行数的性能。
鉴于查询的整体状态,可能值得探索重写以将查询分解为更小的部分,以识别您感兴趣的唯一键集,然后获取您感兴趣的完整列集: