排除加速数据库恢复故障
适用于: sql Server 2019 (15.x) 及更高版本Azure SQL 数据库Azure SQL 托管实例 Microsoft Fabric 中的 SQL 数据库
本文可帮助诊断 sql Server 2019 (15.x) 及更高版本中 加速数据库恢复 (ADR) 的问题,以及 Microsoft Fabric 中的 Azure SQL 托管实例、Azure SQL 数据库和 SQL 数据库。
检查 PVS 的大小
使用 sys.dm_tran_persistent_version_store_stats DMV 来确定持久性版本存储(PVS)大小是否大于预期。
以下示例查询显示有关当前 PVS 大小、清理过程和其他详细信息:
SELECT DB_NAME(pvss.database_id) AS database_name,
pvss.persistent_version_store_size_kb / 1024. / 1024 AS persistent_version_store_size_gb,
100 * pvss.persistent_version_store_size_kb / df.total_db_size_kb AS pvs_pct_of_database_size,
df.total_db_size_kb/ 1024. / 1024 AS total_db_size_gb,
pvss.online_index_version_store_size_kb / 1024. / 1024 AS online_index_version_store_size_gb,
pvss.current_aborted_transaction_count,
pvss.aborted_version_cleaner_start_time,
pvss.aborted_version_cleaner_end_time,
dt.database_transaction_begin_time AS oldest_transaction_begin_time,
asdt.session_id AS active_transaction_session_id,
asdt.elapsed_time_seconds AS active_transaction_elapsed_time_seconds,
pvss.pvs_off_row_page_skipped_low_water_mark,
pvss.pvs_off_row_page_skipped_min_useful_xts,
pvss.pvs_off_row_page_skipped_oldest_aborted_xdesid
FROM sys.dm_tran_persistent_version_store_stats AS pvss
CROSS APPLY (
SELECT SUM(size * 8.) AS total_db_size_kb
FROM sys.database_files
WHERE state = 0
AND
type = 0
) AS df
LEFT JOIN sys.dm_tran_database_transactions AS dt
ON pvss.oldest_active_transaction_id = dt.transaction_id
AND
pvss.database_id = dt.database_id
LEFT JOIN sys.dm_tran_active_snapshot_database_transactions AS asdt
ON pvss.min_transaction_timestamp = asdt.transaction_sequence_num
OR
pvss.online_index_min_transaction_timestamp = asdt.transaction_sequence_num
WHERE pvss.database_id = DB_ID();
检查 pvs_pct_of_database_size
列以查看 PVS 相对于数据库总大小的大小。 注意与典型 PVS 大小的任何差异(与其他应用程序活动期间呈现的基线相比)。 如果 PVS 明显大于基线,或者接近数据库大小的 50%,则 PVS 被视为较大。 请使用以下故障排除步骤查找 PVS 较大的原因。
如果 PVS 大小大于预期,请检查以下内容:
检查长时间运行的活动事务
长时间运行的活动事务可能会阻止已启用 ADR 的数据库中的 PVS 清理。 使用 oldest_transaction_begin_time
列检查最早的活动事务的开始时间。 有关长时间运行的事务的详细信息,请使用以下示例查询。 可以为事务持续时间和生成的事务日志量设置阈值:
DECLARE @LongTxThreshold int = 1800; /* The number of seconds to use as a duration threshold for long-running transactions */
DECLARE @LongTransactionLogBytes bigint = 1073741824; /* The number of bytes to use as a log amount threshold for long-running transactions */
SELECT dbtr.database_id,
transess.session_id,
transess.transaction_id,
atr.name,
sess.login_time,
dbtr.database_transaction_log_bytes_used,
CASE WHEN GETDATE() >= DATEADD(second, @longTxThreshold, tr.transaction_begin_time) THEN 'DurationThresholdExceeded'
WHEN dbtr.database_transaction_log_bytes_used >= @LongTransactionLogBytes THEN 'LogThresholdExceeded'
ELSE 'Unknown'
END AS Reason
FROM sys.dm_tran_active_transactions AS tr
INNER JOIN sys.dm_tran_session_transactions AS transess
ON tr.transaction_id = transess.transaction_id
INNER JOIN sys.dm_exec_sessions AS sess
ON transess.session_id = sess.session_id
INNER JOIN sys.dm_tran_database_transactions AS dbtr
ON tr.transaction_id = dbtr.transaction_id
INNER JOIN sys.dm_tran_active_transactions AS atr
ON atr.transaction_id = transess.transaction_id
WHERE GETDATE() >= DATEADD(second, @LongTxThreshold, tr.transaction_begin_time)
OR
dbtr.database_transaction_log_bytes_used >= @LongTransactionLogBytes;
确定会话后,请考虑将其终止(如果允许)。 查看应用程序以确定有问题的活动事务的性质,以避免将来出现问题。
有关排查长期运行的查询故障的详细信息,请参阅:
检查长时间运行的活动快照扫描
长时间运行的活动快照扫描可能阻止已启用 ADR 的数据库中的 PVS 清理。 使用 READ COMMITTED
快照隔离 (RCSI) 或SNAPSHOT
隔离级别的语句接收实例级时间戳。 快照扫描使用时间戳来决定 RCSI 或 SNAPSHOT
事务的版本行可见性。 使用 RCSI 的每个语句都有其自己的时间戳,而 SNAPSHOT
隔离具有事务级时间戳。
这些实例级事务时间戳即使在单数据库事务中使用,因为任何事务都可能会提示跨数据库事务。 因此,快照扫描可以阻止在同一数据库引擎实例上的任何数据库中的 PVS 清理。 同样,如果未启用 ADR,快照扫描可能会阻止清理 tempdb
中的版本存储。 因此,当存在使用 SNAPSHOT
或 RCSI 的长时间运行的事务时,PVS 可能会变大。
在本文开头的故障排除查询 中,pvs_off_row_page_skipped_min_useful_xts
列显示由于快照扫描时间过长而跳过回收的页数。 如果此列中的值高于正常水平,则表示较长时间的快照扫描会干扰PVS的清理过程。
请使用以下示例查询来查找具有长时间运行的 SNAPSHOT
或 RCSI 事务的会话:
SELECT snap.transaction_id,
snap.transaction_sequence_num,
session.session_id,
session.login_time,
GETUTCDATE() AS [now],
session.host_name,
session.program_name,
session.login_name,
session.last_request_start_time
FROM sys.dm_tran_active_snapshot_database_transactions AS snap
INNER JOIN sys.dm_exec_sessions AS session
ON snap.session_id = session.session_id
ORDER BY snap.transaction_sequence_num ASC;
为防止 PVS 清理延迟:
- 如果可能,请考虑终止延迟 PVS 清理的长期活动的事务会话。
- 优化长时间运行的查询以缩短查询持续时间。
- 查看应用程序以确定有问题的活动快照扫描的性质。 对于延迟 PVS 清理的长时间运行查询,请考虑使用不同的隔离级别,例如
READ COMMITTED
,而不是SNAPSHOT
或 RCSI。 在SNAPSHOT
隔离级别中,此问题更频繁地发生。 - 在 Azure SQL 数据库弹性池中,请考虑使用
SNAPSHOT
隔离或 RCSI 将具有长时间运行事务的数据库移出弹性池。
检查辅助副本上的长时间运行查询
如果数据库具有辅助副本,请检查辅助低水印是否在前进。
在主要副本上运行以下 DMV,以识别辅助副本上可能阻止 PVS 清理的长时间运行查询:
- SQL Server 和 Azure SQL 托管实例的 sys.dm_hadr_database_replica_states
low_water_mark_for_ghosts
列中的 sys.dm_database_replica_states(适用于 Azure SQL 数据库和 Microsoft Fabric 中的 SQL 数据库)。
在 sys.dm_tran_persistent_version_store_stats DMV 中,pvs_off_row_page_skipped_low_water_mark
列还可以指示由于辅助副本上的长时间运行查询而出现清理延迟。
连接到辅助副本,找到正在运行长时间查询的会话,并在允许的情况下考虑终止该会话。 辅助副本上的长持续运行查询可能会阻碍 PVS 清理以及阻止虚影清除。
检查是否存在大量中止的交易
如果上述任何方案都不适用于你的工作负载,则清理很可能会由于大量中止事务而被延迟。 检查 aborted_version_cleaner_last_start_time
和 aborted_version_cleaner_last_end_time
列以查看上次中止的事务清理是否已完成。 中止事务清理完成后,oldest_aborted_transaction_id
应会移到更高的位置。 如果 oldest_aborted_transaction_id
远低于 oldest_active_transaction_id
,并且 current_abort_transaction_count
具有较大值,则可能存在阻止 PVS 清理的旧终止事务。
若要处理大量中止的事务,请考虑以下事项:
- 如果可能,请停止工作负载,以便版本清理工具取得进展。
- 优化工作负荷以减少对象级锁。
- 查看应用程序以识别高事务中止率问题。 中止可能来自高死锁率、重复键、约束冲突或查询超时。
- 如果使用 SQL Server,请禁用 ADR 作为仅紧急步骤来控制 PVS 大小。 请参阅禁用 ADR。
- 如果最近未成功完成中止的事务清理,请检查错误日志中是否存在报告
VersionCleaner
问题的消息。 - 如果 PVS 大小在清理完成后未按预期减小,请检查
pvs_off_row_page_skipped_oldest_aborted_xdesid
列。 较大的值表示空间仍被中止事务的行版本占用。
手动启动 PVS 清理进程
如果工作负载具有大量 DML 语句(INSERT
、UPDATE
、DELETE
、MERGE
),例如大容量 OLTP,则 PVS 清理过程可能需要一段时间的休息/恢复才能回收空间。
若要在工作负载之间或维护时段内手动激活 PVS 清理进程,请使用系统存储过程 sys.sp_persistent_version_cleanup。
例如:
EXEC sys.sp_persistent_version_cleanup [WideWorldImporters];
捕获清理失败
从 SQL Server 2022(16.x 开始),PVS 清理行为记录在错误日志中。 通常,这会导致每 10 分钟记录一次新的日志事件。 tx_mtvc2_sweep_stats
扩展事件也会报告清理统计信息。