这是一个 SQL Server 2016 CU2 实例,配置了 15 GB 作为最大 RAM 使用量。MDOP 为 4。此实例中的数据库很少被用户查询,并且这是一个只读辅助副本。
问题:每周,所有查询都会因内存耗尽而进入 RESOURCE_SEMAPHORE 状态,即使此服务器中没有其他查询同时运行。实例重新启动后,查询会重新开始工作。通过下图,您会注意到我们缺少最大工作区内存,这些查询真的非常糟糕(天文数字般的查询成本)。
重启前:可用的最大工作区内存仅有 1.8 GB,并且所有错误查询都进入 RESOURCE_SEMAPHORE 状态。
实例重启后:有大量工作区内存(~11GB)并且不再有 RESOURCE_SEMAPHORE,即使对于糟糕的查询也是如此。
如您所见,这是一个令人反感的查询,要求大约 2GB 的 RAM。在此图中,SSMS 显示所需的内存实际上已授予 - 因为实例已重新启动。在重新启动之前,内存授予仍为 NULL,查询处于 RESOURCE_SEMAPHORE 等待状态。
现在,我们想知道的是:为什么最大工作区内存会随着时间的推移而减少,并且在没有查询运行时不会被释放?
答案1
看起来,在总共分配的 15,728,640,000 字节内存中,被盗服务器内存占用了 12,828,864,000 字节,显然没有足够的内存用于正常运行。
文档中说 SQL Server,内存管理器对象:
被盗服务器内存 (KB)
指定服务器用于数据库页面之外的其他用途的内存量。
一个回答说得更多:
被盗内存是指用于排序或哈希操作(查询工作区内存)的缓冲区,或用于分配通用内存存储以存储内部数据结构(例如锁、事务上下文和连接信息)的缓冲区。惰性写入器进程不得将被盗缓冲区从缓冲池中清除。
浪费的查询显然执行了巨大的排序操作,然后 SQL Server 不会释放分配的内存。内存取自缓冲池,不能用于其他任何用途。
你的选择并不多:
- 改进该查询,使其不对大量数据进行排序
- 为 SQL Server 添加更多内存
- 定期重新启动 SQL Server,尤其是在运行此查询后。