SQL Server 2016中log_reuse_wait_desc显示ACTIVE_TRANSACTION但DBCC OPENTRAN无结果
排查SQL Server中log_reuse_wait_desc显示ACTIVE_TRANSACTION但DBCC OPENTRAN无结果的问题
遇到这种情况确实挺头疼的——明明log_reuse_wait_desc显示有活跃事务,但DBCC OPENTRAN却找不到任何结果。结合你提到的数据库有定期爬取的全文目录,大概率是系统后台事务在搞鬼,毕竟DBCC OPENTRAN只专注于用户发起的长时间运行事务,像全文索引爬取这类系统级后台任务的事务,它通常不会展示出来。下面给你一套具体的排查和验证步骤:
1. 用DMV捕获所有活跃事务(包括系统/后台事务)
直接用动态管理视图(DMV)关联查询,能抓到DBCC OPENTRAN遗漏的事务:
SELECT t.transaction_id, t.name AS transaction_name, t.transaction_begin_time, s.session_id, s.login_name, s.host_name, s.program_name, st.text AS active_sql_text FROM sys.dm_tran_active_transactions t JOIN sys.dm_tran_session_transactions stt ON t.transaction_id = stt.transaction_id JOIN sys.dm_exec_sessions s ON stt.session_id = s.session_id LEFT JOIN sys.dm_exec_requests r ON s.session_id = r.session_id CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st ORDER BY t.transaction_begin_time DESC;
重点关注:
program_name列中带有Full-text相关字样的会话(比如SQL Server Full-text Filter Daemon Launcher)- 事务开始时间较早的记录,这类往往是长时间持有的后台事务
2. 直接检查全文索引的爬取状态
既然你提到有定期爬取的全文目录,直接验证它是否在运行:
SELECT fc.catalog_name, t.table_name, fi.crawl_type, fi.crawl_start_date, fi.crawl_end_date, fi.crawl_status FROM sys.fulltext_catalogs fc JOIN sys.fulltext_indexes fi ON fc.fulltext_catalog_id = fi.fulltext_catalog_id JOIN sys.tables t ON fi.object_id = t.object_id WHERE fi.crawl_status IN (0, 1); -- 0=正在爬取,1=暂停未完成
如果返回结果中crawl_status为0,说明当前正有全文爬取在运行,这个后台任务会持有事务,正是导致log_reuse_wait_desc显示ACTIVE_TRANSACTION的原因。
3. 定位阻止数据库脱机的会话
如果数据库无法脱机,用下面的查询找到阻塞源:
SELECT r.blocking_session_id, r.session_id, r.command, r.resource_type, r.resource_description, st.text AS sql_text FROM sys.dm_exec_requests r CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) st WHERE r.database_id = DB_ID('AdventureWorks') AND r.blocking_session_id != 0;
或者用经典的sp_who2快速查看:
EXEC sp_who2;
查看结果中BlkBy列不为0的会话,就能找到阻止数据库脱机的源头。
4. 验证全文爬取是否是事务持有源
如果前面的查询找到了全文相关的会话,用下面的语句确认它关联的事务:
SELECT t.transaction_id, t.transaction_begin_time, s.program_name, s.login_name FROM sys.dm_tran_active_transactions t JOIN sys.dm_tran_session_transactions stt ON t.transaction_id = stt.transaction_id JOIN sys.dm_exec_sessions s ON stt.session_id = s.session_id WHERE s.program_name LIKE '%Full-text%';
后续处理建议
- 如果确认是全文爬取导致的,可以等待爬取完成(再次执行步骤2的查询,看
crawl_end_date是否更新),或者手动暂停爬取:
ALTER FULLTEXT CATALOG [你的全文目录名称] STOP POPULATION;
- 暂停后再次查询
sys.databases的log_reuse_wait_desc,确认是否变回NOTHING,之后尝试脱机数据库。 - 长期来看,可以调整全文爬取的调度时间,避开数据库维护窗口;或者改用增量爬取代替全量爬取,减少事务持有的时长。
内容的提问来源于stack exchange,提问作者d-_-b
相关产品推荐
相关产品推荐

