本文提供了解决与内存优化 tempdb
元数据功能相关的内存不足问题的解决方案。
现象
启用内存优化 tempdb
元数据(HkTempDB)功能后,可能会看到错误 701 ,指示分配和 SQL Server 服务崩溃的内存不足异常 tempdb
。 此外,你可能会看到用于内存中 OLTP(Hekaton)的内存分配器 MEMORYCLERK_XTP
正在逐渐或迅速增长,并且不会缩减。 随着 XTP 内存的增长而没有上限,SQL Server 中会显示以下错误消息:
由于资源池“default”中的内存不足,禁止为数据库“tempdb”分配页面。 有关更多信息,请参阅 '
http://go.microsoft.com/fwlink/?LinkId=510837
'。
在 DMV dm_os_memory_clerks上运行MEMORYCLERK_XTP
例如:
SELECT type, memory_node_id, pages_kb
FROM sys.dm_os_memory_clerks
WHERE type = 'MEMORYCLERK_XTP'
结果:
type memory_node_id pages_kb
------------------------------------------------------------ -------------- --------------------
MEMORYCLERK_XTP 0 60104496
MEMORYCLERK_XTP 64 0
诊断问题
若要收集数据来诊断问题,请执行以下步骤:
收集轻型跟踪或扩展事件(XEvent)以了解
tempdb
工作负荷,并找出工作负荷是否有任何长时间运行的显式事务以及临时表上的 DDL 语句。收集以下 DMV 的输出以进一步分析。
SELECT * FROM sys.dm_os_memory_clerks SELECT * FROM sys.dm_exec_requests SELECT * FROM sys.dm_exec_sessions -- from tempdb SELECT * FROM tempdb.sys.dm_xtp_system_memory_consumers SELECT * FROM tempdb.sys.dm_db_xtp_memory_consumers SELECT * FROM tempdb.sys.dm_xtp_transaction_stats SELECT * FROM tempdb.sys.dm_xtp_gc_queue_stats SELECT * FROM tempdb.sys.dm_db_xtp_object_stats SELECT * FROM tempdb.sys.dm_db_xtp_transactions SELECT * FROM tempdb.sys.dm_tran_session_transactions SELECT * FROM tempdb.sys.dm_tran_database_transactions SELECT * FROM tempdb.sys.dm_tran_active_transactions
原因和解决方法
使用 DMV 验证原因时,你可能会看到问题的不同情况。 这些方案可以分为以下两个类别。 若要解决此问题,可以对每个方案使用相应的解决方法。 有关如何缓解此问题的详细信息,请参阅 缓解步骤以检查内存优化 tempdb 元数据内存。
XTP 内存消耗逐渐增加
方案 1
DMV tempdb.sys.dm_xtp_system_memory_consumers 或 tempdb.sys.dm_db_xtp_memory_consumers 显示已分配字节和已用字节之间的较大差异。
解决方法:若要解决此问题,可以在 SQL Server 2019 CU13、SQL Server 2022 CU1 或更高版本中运行以下命令,该版本具有释放已分配但未使用的字节的新过程
sys.sp_xtp_force_gc
。注意
从 SQL Server 2022 CU1 开始,只需执行一次存储过程。
/* Yes, 2 times for both*/ EXEC sys.sp_xtp_force_gc 'tempdb' GO EXEC sys.sp_xtp_force_gc 'tempdb' GO EXEC sys.sp_xtp_force_gc GO EXEC sys.sp_xtp_force_gc
方案 2
DMV
tempdb.sys.dm_xtp_system_memory_consumers
显示内存使用者类型VARHEAP
和LOOKASIDE
已分配和已用字节的字节数值较高。解决方法:检查涉及临时表上的 DDL 语句的显式长时间运行的事务,并通过保持事务短来从应用程序端解决。
注意
若要在测试环境中重现此问题,可以在临时表(s)上使用数据定义语言(DDL)语句创建显式 事务 ,并在其他活动发生时长时间保持打开状态。
方案 3
DMV
tempdb.sys.dm_db_xtp_memory_consumers
在大型对象(LOB)分配器或表堆中显示已分配和已用字节的高值,Object_ID
其中XTP_Object_ID
,以及是Index_ID
NULL
。方案 4
不断增加“VARHEAP\Storage 内部堆”的 XTP 数据库内存消耗导致出现内存不足错误 41805。
解决方法:已在 SQL Server 17 CU25 及更高版本中识别和解决的问题 14087445正在审查中,以便移植到 SQL Server 2019。
XTP 内存消耗突然激增或快速增加
方案 5
DMV
tempdb.sys.dm_db_xtp_memory_consumers
在表堆中显示已分配或已用字节的高值,其中Object_ID
不是NULL
。 此问题的最常见原因是在临时表上使用 DDL 语句长时间运行的显式打开事务。 例如:BEGIN TRAN CREATE TABLE #T(sn int) … … COMMIT
对临时表使用 DDL 语句的显式开启的事务不会允许通过使用
tempdb
元数据释放表堆和查找堆,以便后续事务使用。解决方法:检查涉及临时表上 DDL 语句的持续时间较长的显式事务,并通过在应用程序端保持事务简短来解决。
控制内存优化 tempdb 元数据内存的缓解步骤
为了避免或解决在临时表上使用 DDL 语句的长时间运行事务,一般建议是保持事务简短。
增加 最大服务器内存 ,以确保在 tempdb 密集型工作负荷的情况下有足够的内存进行操作。
定期运行
sys.sp_xtp_force_gc
。若要防止服务器可能内存不足的情况,可以将 tempdb 绑定到 资源调控器资源池。 例如,使用
MAX_MEMORY_PERCENT = 30
创建一个资源池。 然后,使用以下 ALTER SERVER CONFIGURATION 命令将资源池绑定到内存优化 tempdb 元数据。ALTER SERVER CONFIGURATION SET MEMORY_OPTIMIZED TEMPDB_METADATA = ON (RESOURCE_POOL = '<PoolName>');
即使已启用内存优化
tempdb
元数据,此更改也需要重启才能生效。 有关详细信息,请参阅:警告
将 HktempDB 绑定到池后,池可能会达到其最大设置,并且使用
tempdb
的任何查询都可能会失败并出现内存不足错误。 例如:由于资源池“HkTempDB”中的内存不足,不允许数据库“tempdb”的页面分配。 有关更多信息,请参阅 '
http://go.microsoft.com/fwlink/?LinkId=510837
'。 由于内存压力,XTP 页面分配失败:FAIL_PAGE_ALLOCATION 8在某些情况下,如果发生内存不足错误,SQL Server 服务可能会停止。 若要降低发生这种情况的可能性,请将内存池
MAX_MEMORY_PERCENT
设置为高值。内存优化
tempdb
元数据功能不支持每个工作负载。 例如,对长时间运行的临时表使用具有 DDL 语句的显式事务将导致所述的方案。 如果工作负荷中有此类事务,并且无法控制其持续时间,则也许此功能不适合你的环境。 使用HkTempDB
之前,应进行广泛测试。
详细信息
这些部分提供有关内存优化 tempdb
元数据中涉及的某些内存组件的详细信息。
Lookaside 内存分配器
内存中 OLTP 中的 Lookaside 是一种线程本地内存分配器,可帮助实现快速事务处理。 每个线程对象都包含一组 lookaside 内存分配器。 与每个线程关联的每个旁视缓冲区都有一个预定义的上限,可以分配的内存量。 达到限制后,线程将从溢出的共享内存池(VARHEAP
)分配内存。 DMV sys.dm_xtp_system_memory_consumers
聚合每个旁路类型(memory_consumer_type_desc = 'LOOKASIDE'
)和共享内存池(memory_consumer_type_desc = 'VARHEAP'
和 memory_consumer_desc = 'Lookaside heap'
)的数据。
系统级使用者:tempdb.sys.dm_xtp_system_memory_consumers
大约 25 种旁路缓存消费者类型是上限。 当线程需要从这些 lookaside 结构获得更多内存时,内存会转移到 lookaside 堆中并得到满足。 已使用字节的高值可能是持续繁重的tempdb
工作负荷和/或长期运行的开放事务(该事务使用临时对象)的指示器。
-- system memory consumers @ instance
SELECT memory_consumer_type_desc, memory_consumer_desc, allocated_bytes, used_bytes
FROM sys.dm_xtp_system_memory_consumers
memory_consumer_type_desc memory_consumer_desc allocated_bytes used_bytes
------------------------- ------------------------------------------ -------------------- --------------------
VARHEAP Lookaside heap 0 0
PGPOOL 256K page pool 0 0
PGPOOL 4K page pool 0 0
VARHEAP System heap 458752 448000
LOOKASIDE Transaction list element 0 0
LOOKASIDE Delta tracker cursor 0 0
LOOKASIDE Transaction delta tracker 0 0
LOOKASIDE Creation Statement Id Map Entry 0 0
LOOKASIDE Creation Statement Id Map 0 0
LOOKASIDE Log IO proxy 0 0
LOOKASIDE Log IO completion 0 0
LOOKASIDE Sequence object insert row 0 0
LOOKASIDE Sequence object map entry 0 0
LOOKASIDE Sequence object values map 0 0
LOOKASIDE Redo transaction map entry 0 0
LOOKASIDE Transaction recent rows 0 0
LOOKASIDE Heap cursor 0 0
LOOKASIDE Range cursor 0 0
LOOKASIDE Hash cursor 0 0
LOOKASIDE Transaction dependent ring buffer 0 0
LOOKASIDE Transaction save-point set entry 0 0
LOOKASIDE Transaction FK validation sets 0 0
LOOKASIDE Transaction partially-inserted rows set 0 0
LOOKASIDE Transaction constraint set 0 0
LOOKASIDE Transaction save-point set 0 0
LOOKASIDE Transaction write set 0 0
LOOKASIDE Transaction scan set 0 0
LOOKASIDE Transaction read set 0 0
LOOKASIDE Transaction 0 0
数据库级使用者:tempdb.sys.dm_db_xtp_memory_consumers
LOB 分配器用于系统表中的 LOB/行外数据。
表堆存储用于存储系统表的行数据。
已用字节的高值可能表明持续的高强度tempdb
工作负荷和/或使用临时对象的长时间未完成事务。