内存优化 tempdb 元数据 (HkTempDB) 内存不足错误
本文提供了解决与内存优化 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)分配器或表堆中显示已分配和已用字节的高值,XTP_Object_ID
其中Object_ID
,以及是Index_ID
NULL
。方案 4
不断增大“VARHEAP\Storage 内部堆”XTP 数据库内存使用者会导致内存不足错误 41805。
解决方法:14087445已在 SQL Server 17 CU25 及更高版本中识别和解决的问题正在审查中,以便移植到 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 堆感到满意。 已用字节的高值可能是使用临时对象的常量繁重 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
工作负荷和/或长时间运行的开放事务的指示器。