SQL Server 诊断检测到由于读取过时或写入丢失而未报告的 I/O 问题

本文介绍SQL Server诊断如何帮助检测因读取过时或写入丢失而导致的未报告输入或输出问题。

原始产品版本:SQL Server
原始 KB 编号: 826433

症状

如果操作系统、驱动程序或硬件问题导致 I/O 路径中的写入丢失或读取条件陈旧,你可能会在SQL Server中看到与数据完整性相关的错误消息,例如错误 605、823、3448 和 3456。 你可能会收到类似于以下示例的错误消息:

2003-07-24 16:43:04.57 spid63 Getpage: bstat=0x9, sstat=0x800, cache
2003-07-24 16:43:04.57 spid63 pageno is/should be: objid is/should be:
2003-07-24 16:43:04.57 spid63 (1:7040966)/(1:7040966) 2093354622/2039782424
2003-07-24 16:43:04.57 spid63 ... IAM indicates that page is allocated to this object
2003-07-24 16:52:37.67 spid63 Error: 605, Severity: 21, State: 1
2003-07-24 16:52:37.67 spid63 Attempt to fetch logical page (1:7040966) in database 'pubs' belongs to object 'authors', not to object 'titles'..
2003-07-24 16:52:40.99 spid63 Error: 3448, Severity: 21, State: 1
2003-07-24 16:52:40.99 spid63 Could not undo log record (63361:16876:181), for transaction ID (0:159696956), on page (1:7040977), database 'pubs' (database ID 12). Page information: LSN = (63192:958360:10), type = 2. Log information: OpCode = 2, context 1..
2003-07-09 14:31:35.92 spid66 Error: 823, Severity: 24, State: 2
2003-07-09 14:31:35.92 spid66 I/O error (bad page ID) detected during read at offset 0x00000016774000 in file 'h:\sql\MSSQL\data\tempdb.mdf'..
2010-02-06 15:57:24.14 spid17s Error: 3456, Severity: 21, State: 1.
2010-02-06 15:57:24.14 spid17s Could not redo log record (58997:5252:28), for transaction ID (0:109000187), on page (1:480946), database 'MyDatabase' (database ID 17). Page: LSN = (58997:5234:17), type = 3. Log: OpCode = 2, context 5, PrevPageLSN: (58997:5243:17). Restore from a backup of the database, or repair the database.

SQL Server 中的新 I/O 诊断功能

SQL Server从 SQL Server 2000 Service Pack 4 开始引入了新的 I/O 诊断功能,此后这些诊断一直是产品的一部分。 这些功能旨在帮助检测与外部 I/O 相关的问题,并排查 症状 部分中所述的错误消息。

如果收到症状部分中列出的任何错误消息,并且这些错误消息未由物理驱动器故障等事件解释,请查看SQL Server、操作系统、驱动程序和硬件的任何已知问题。 诊断尝试提供有关以下两个条件的信息:

  • 丢失写入:成功调用 WriteFile API,但操作系统、驱动程序或缓存控制器不会将数据正确刷新到物理媒体,即使SQL Server通知写入成功。

  • 过时读取:成功调用 ReadFile API,但操作系统、驱动程序或缓存控制器会错误地返回旧版数据。

为了说明,Microsoft 已确认以下场景:WriteFile API 调用返回成功状态,但立即成功读取同一数据块会返回旧数据,包括可能存储在硬件读取缓存中的数据。 有时,由于读取缓存问题,会出现此问题。 在其他情况下,写入数据永远不会写入物理磁盘。

如何启用诊断

在 SQL Server 2017 及更高版本中,默认启用此诊断功能。 在 SQL Server 2016 及更低版本中,只能使用跟踪标志 818 启用这些诊断。 可以为 SQL Server 实例指定跟踪标志 818 作为启动参数 -T818,也可以运行以下 T-SQL 语句,以便在运行时启用它们:

DBCC TRACEON(818, -1)

跟踪标志 818 启用内存中环形缓冲区,用于跟踪运行SQL Server的计算机执行的最后 2,048 次成功写入操作,不包括排序和工作文件 I/O。 发生 605、823 或 3448 等错误时,传入缓冲区的日志序列号 (LSN) 值与最近的写入列表进行比较。 如果在读取操作期间检索到的 LSN 早于写入操作中使用的 LSN,则会在SQL Server错误日志中记录新的错误消息。 大多数SQL Server写入操作都作为检查点或延迟写入发生, (延迟写入是使用异步 I/O) 的后台任务。 环形缓冲区的实现是轻型的,对系统的性能影响可以忽略不计。

有关错误日志中消息的详细信息

以下消息不会显示来自 WriteFile API 或 ReadFile API 调用的任何显式错误,SQL Server。 相反,它显示查看 LSN 时产生的逻辑 I/O 错误,并且其预期值不正确:

从 SQL Server 2005 开始,显示的错误消息为:

SQL Server检测到基于逻辑一致性的 I/O 错误:读取过时。 在文件 <FILE NAME>中的偏移<PHYSICAL OFFSET>量处,在数据库 ID <DBID> 的 页<PAGEID>的 中<Read/Write>发生。 SQL Server错误日志或系统事件日志中的其他消息可能会提供更多详细信息。 这是威胁数据库完整性的严重错误情况,必须立即更正。 检查 (DBCC CHECKDB) 完成完整的数据库一致性。 此错误可能由许多因素引起。 有关详细信息,请参阅联机丛书SQL Server。

有关错误 824 的详细信息,请参阅 MSSQLSERVER_824

在发生或报告此错误时,读取缓存包含旧版页面,或者数据未正确写入物理磁盘。 无论哪种情况 (写入丢失或读取) 过时,SQL Server报告操作系统、驱动程序或硬件层的外部问题。

如果尝试回滚具有错误 605 或 823 的事务时出现错误 3448,则 SQL Server 实例会自动关闭数据库并尝试打开并恢复该数据库。 遇到错误 605 或 823 的第一页被视为错误页面,并且页面 ID 由运行SQL Server的计算机保留。 在恢复 (之前,重做阶段) 读取错误的页 ID 时,有关页眉的主要详细信息记录在SQL Server错误日志中。 此操作非常重要,因为它有助于区分“丢失写入”和“过时读取”方案。

观察到过时读取和写入丢失的行为

在过时的读取方案中,你可能会看到以下两种常见行为:

  • 如果数据库文件处于关闭状态,然后打开,则在恢复期间将返回正确的最近写入的数据。

  • 发出检查点并运行 DBCC DROPCLEANBUFFERS 语句 (从内存) 中删除所有数据库页,然后在 DBCC CHECKDB 数据库上运行 语句时,将返回最近写入的数据。

上一段落中提到的行为表示读取缓存问题,并且经常通过禁用读取缓存来解决这些问题。 上一段落中概述的操作通常会强制缓存失效,而成功发生的读取表明物理媒体已正确更新。 当读回的页面仍然是旧版数据时,即使在强制刷新缓存机制之后,也会发生写入行为丢失的情况。

有时,问题可能不是特定于硬件缓存。 这可能是筛选器驱动程序的问题。 在这种情况下,请查看你的软件(包括备份实用工具和防病毒软件),然后查看筛选器驱动程序是否存在问题。

各种过时读取和丢失写入方案的说明

Microsoft 还记录了不符合错误 605 或 823 条件,但由相同的过时读取或丢失写入活动引起的条件。 在某些情况下,页面似乎更新了两次,但具有相同的 LSN 值。 如果对象 ID 和页 ID 正确, (页已分配给对象) ,并且对页面进行了更改并刷新到磁盘,则可能会出现此行为。 下一页检索将返回较旧的图像,然后进行第二次更改。 SQL Server事务日志显示页面更新了两次,其 LSN 值相同。 尝试还原事务日志序列或出现数据一致性问题(例如外键故障或缺少数据条目)时,此操作将成为一个问题。 以下错误消息说明了这种情况的一个示例:

错误: 3456,严重性: 21,状态: 1 无法重做日志记录 (276666:1664:19) ,对于事务 ID (0:825853240) ,在页 (1:1787100) ,数据库“作者” (7) 。 页面:LSN = (276658:4501:9) ,类型 = 1。 日志:OpCode = 4,上下文 2,PrevPageLSN: (275565:3959:31) 。

以下列表中更详细地概述了某些方案:

LSN SequenceAction
1   Checkpoint
2   Begin Transaction
3   Table created or truncated
4   Inserts (Pages allocated)
5   Newly allocated page written to disk by Lazy Writer
6   Select from table - Scans IAM chain, newly allocated page read back from disk (LRU | HASHED = 0x9 in getpage message), encounters Error 605 - Invalid Object ID
7   Rollback of transaction initiated
LSN SequenceAction
1   Checkpoint
2   Begin Transaction
3   Page Modification
4   Page written to disk by Lazy Writer
5   Page read in for another modification (stale image returned)
6   Page Modified for a second time but because of stale image does not see first modification 
7   Rollback - Fails - Transaction Log shows two different log records with the same PREV LSN for the page

sort SQL Server运算符执行 I/O 活动,通常在数据库中tempdb。 这些 I/O 操作类似于缓冲区 I/O 操作;但是,它们已设计为使用读取重试逻辑来尝试解决类似问题。 本文中介绍的其他诊断不适用于这些 I/O 操作。

Microsoft 指出,以下排序读取失败的根本原因是读取过时或写入丢失:

2003-04-01 20:13:31.38 spid122 SQL Server Assertion: File: <p:\sql\ntdbms\storeng\drs\include\record.inl>, line=1447 Failed Assertion = 'm_SizeRec > 0 && m_SizeRec <= MAXDATAROW'.
2003-03-29 09:51:41.12 spid57 Sort read failure (bad page ID). pageid = (0x1:0x13e9), dbid = 2, file = e:\program files\Microsoft SQL Server\mssql\data\tempdb.mdf. Retrying.
2003-03-29 09:51:41.13 spid57 Error: 823, Severity: 24, State: 7
2003-03-29 09:51:41.13 spid57 I/O error (bad page ID) detected during read at offset 0x000000027d2000 in file 'e:\program files\Microsoft SQL Server\mssql\data\tempdb.mdf'..
* 00931097 Module(sqlservr+00531097) (utassert_fail+000002E3)
* 005B1DA8 Module(sqlservr+001B1DA8) (RecBase::Resize+00000091)
* 00407EE7 Module(sqlservr+00007EE7) (RecBase::LocateColumn+00000012)
* 00852520 Module(sqlservr+00452520) (mergerow+000000A4)
* 008522B3 Module(sqlservr+004522B3) (merge_getnext+00000285)
* 0085207D Module(sqlservr+0045207D) (mergenext+0000000D)
* 004FC5FB Module(sqlservr+000FC5FB) (getsorted+00000021)

由于过时的读取或写入丢失会导致数据存储超出预期,因此可能会出现各种行为。 它可能显示为缺失数据,但缺失数据的某些更常见影响显示为索引损坏,例如错误 644 或 625:

错误 644 严重级别 21 消息文本在索引页 %S_PGID、索引 ID %d、数据库 '%.*ls' 中找不到 RID '%.*hs' 的索引项。

错误 625 严重级别 21 消息文本无法通过 RID 从 %S_PGID 页检索行,因为 slotid (%d) 无效。

某些客户在执行行计数活动后报告了缺少行。 出现此问题的原因是写入丢失。 也许,该页应该链接到聚集索引页链。 如果写入在物理上丢失,数据也会丢失。

重要

如果你遇到任何行为,或者怀疑存在类似问题以及禁用缓存机制,Microsoft 强烈建议你获取SQL Server的最新更新。 Microsoft 还强烈建议你对操作系统及其相关配置进行严格审查。

请注意,Microsoft 已确认,在极少数且繁重的 I/O 负载下,某些硬件平台可能会返回过时的读取。 如果扩展诊断指示可能已过时的读取或写入丢失情况,请与硬件供应商联系,以便立即跟进并使用 SQLIOSim 实用工具进行测试。

SQL Server要求系统支持向稳定介质的有保证交付,如SQL Server I/O 可靠性计划要求中所述。 有关SQL Server数据库引擎的输入和输出要求的详细信息,请参阅Microsoft SQL Server 数据库引擎输入/输出要求