由于内存压力,AppDomain 2 SSISDB 被标记为卸载

Don*_*Don 4 sql-server memory sql-server-2019

我有一个存储过程,它将三个大表连接在一起(每个大约有 2000 万条记录)并将记录加载到临时表中。然后将临时表中的数据合并到一个包含大约 6000 万条记录的现有表中。

服务器脱机并显示以下错误消息:

由于内存压力,AppDomain 2 (SSISDB.dbo.[runtime].1] 被标记为卸载。

错误日志消息

使服务器重新联机后,我重新启动了 SQL 服务以清除可能一直存在的所有进程。再次开始工作,它毫无问题地完成了。

我正在运行具有 128GB RAM 的 SQL Server 2019。64 位虚拟服务器上的最大服务器内存为 117964MB。有人在任务管理器中告诉我内存使用率为 94%,这可能是问题所在。但是 SQL 不会占用所有可用内存并保留它吗?所以这似乎是按预期运行的。

sp_WhoIsActive揭示了一些状态为 'Suspended' 和 'Awaiting_Command' 的查询,但我认为这些没有太大影响。128GB 的​​内存似乎足够了,但我想这与它被要求做的工作有关。知道如何排除故障或防止再次发生吗?

服务器的数据驱动器约为1.6TB。连接中的两个较大的数据库是 10GB 的 1900 万行和 13GB 的 2000 万行。那些进入一个临时表,然后MERGE进入一个 26GB 的表,有 5300 万行。

请求的内存授予为 45GB,实际为 30GB。这份工作在正常工作时间之外运行,所以应该没有竞争查询,但我不能 100% 确认有人没有工作到很晚。

我确实注意到它也必须做 a CONVERT_IMPLICIT。这对所需的内存有重大影响吗?

查询计划链接:https : //www.brentozar.com/pastetheplan/?id=SyXaty7xK

Eri*_*ing 10

关于您的服务器

尽管授予了 29 GB 内存,但此查询在两个地方严重溢出。这是在最大服务器内存设置为 115 GB 的情况下,查询可以在您的系统上要求的最高值。

这种大小的内存授予的原因是优化器估计它将需要对 46 GB 的数据进行排序:

坚果

您可以通过查看资源调控器来查看内存授予百分比的详细信息——单个查询可以请求大约 25% 的最大服务器内存设置——并且最多三个查询可以同时请求完全授予。

您获得了这种大小的授权,但仍然会看到这种规模和时间消耗的溢出,这可能意味着就内存而言,您的服务器配置远远不足。

坚果

由于这两个运算符都在批处理模式下执行,因此您看到的时间是每个 operator

我敢肯定,如果你看了等待统计数据此服务器(提供的1.6 TB的数据),PAGEIOLATCH_就在那里,伴随着潜在的SLEEP_TASK或者IO_COMPLETION如果这种规模的泄漏是常见的。虽然这两种等待也可能与其他事情相关联,但我经常看到它们在像你这样的情况下堆积如山。

我首先建议为您的服务器添加更实际的内存量。我不知道这个数字是多少(我不能在这里告诉你),但我可能会根据数据的大小而不是别的什么来达到 512 GB 或更高的目标。您还应该打开内存中的锁定页面(如果尚未启用)。

关于您的查询

我看不到全文,因为查询计划中出现的所有内容都是插入选择列表的一部分,但考虑到它的样子,我可以对整体代码质量做出一些合理的假设。

例如,有几个连接在表达式上,这可能表明您将连接列包装在诸如rtrim或之类的函数中isnull

坚果

但是您的主要问题是在查询结束时和上图所示的溢出。

让我们来谈谈那些!

哈希连接

Hash Join 是为DISTINCT您在143 列查询中抛出的。这让我感到毛骨悚然,如果他们打算继续使用 SQL Server,那么写这篇文章的人应该强烈考虑接受一些培训。

我建议找到生成唯一行的较小的列组合,并使用row_number来标记它们,就像我在此视频中显示的那样:

伪代码示例如下所示:

WITH 
   cte AS
(
   SELECT
       *,
        n = 
            ROW_NUMBER..
    FROM ...
)
SELECT
    c.*
FROM cte AS c
WHERE c.n = 1;
Run Code Online (Sandbox Code Playgroud)

只需确保您的索引适合支持窗口功能。

种类

排序就在那里,因为您的#temp表上有一个聚集索引。

坚果

如果您改为将表创建为堆,并稍后添加索引,则可以避免在查询运行时出现这种不愉快,尽管根据各种本地因素,添加索引可能并不有趣。

如果可能的话,我还建议tablock为您的插入添加一个提示,以鼓励完全平行的插入。

现在,您的查询在插入之前是单线程的,这肯定会损害此行数的性能。

坚果

鉴于查询的整体状态,可能值得探索重写以将查询分解为更小的部分,以标识您感兴趣的唯一键集,然后获取您感兴趣的完整列集: