前言:数据库越大,使用时间越长,貌似稳定性也在逐步下降。数据页逻辑错误,可能是DBA遇到比较棘手的问题之一,本文将基于实战模式给出一些检查及处理的方法。当然,任何方法都是受制于环境的限制,本文中介绍的方法也只适用于某些特定环境,仅供参考;
===================华丽丽的分割线========================
前几天碰到一个错误,具体信息如下:
SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid 不正确(应为 6:49413777,但实际为 0:0)。在文件 'M:/SQLDATA/Pk_4.ndf' 中、偏移量为 0x00005e3fd22000 的位置对数据库 ID 5 中的页 (6:49413777) 执行 读取 期间,发生了该错误。SQL Server 错误日志或系统事件日志
或许这是DBA遇到比较棘手的问题之一了。万幸的是,发生错误的数据库是一个事务复制环境中的订阅库,而且有负载均衡扛着,基本上对业务没有影响;
1、发现该错误后,第一反应是存储(楼主的土豪公司用的是IO卡)出现逻辑错误,尝试手动重启服务器,让IO卡进行自检;进入系统后,发现问题没有解决;
这一步,在IO卡自检完成进入系统后,需要进一步使用厂商提供的监控程序检查IO卡是否有物理坏块,并收集相关日志。经过其他同事检查,IO卡没有异常报错;
2、通过我们的监控工具定位到publication是位于Publisher_A的pk_order_BEQ_new,该publication中涉及3个表
Order_A / Order_B / Order_C
3、在出现问题的机器上(以下称为subscriber_A)通过select count(1) from table_name(nolock)的方式快速检测具体是哪个表有问题;
此处的检测方法有局限性,初步分析如下:
a) 如果是小表,可能在页损坏之前有类似操作,导致全部页还在缓存区中,因而select count(1)是可以获取结果的,无法判断出该表是否存页损坏;
b) 如果IAM页中还有6:49413777的信息,且该页还在缓存区中,也是无法判断出该表是否存页损坏;
c) 如果IAM页中没有6:49413777的信息,则select count(1)的时候会跳过已损坏的页,仍然可以获取结果,也是无法判断出该表是否存页损坏;
只有当IAM页中有6:49413777的信息,而该页又被交换出缓存区,需要进行物理读的时候,才会导致select count(1)无法获取结果,具体情况如下:
此处检测 Order_A正常,Order_B报错;但这只能证明Order_B表确实存在损坏的页,而Order_A却不能断定一定是正常的;
当时的检测办法只是按照select count(1)的方式,判断出Order_B表存在坏页;但实际上,可以从Publisher_A的distribution.dbo.msrepl_errors中获取当前由复制引起的无法写入损坏页的XACT_Seqno,进而通过sp_browsereplcmds ‘XACT_Seqno’,’ XACT_Seqno’,及command_id定位到具体引起该错误的对象名、操作类型和主键值;
但此方法也有弊端,由于页中可能存在多条记录,如果是页头损坏,将导致该页中的所有记录都无法读取,而msrepl_errors重试间隔大约1分钟,所以通过此方法确定损坏的数据页较慢;
4、通过distribution.dbo.msrepl_errors定位到orderexpend_pop表也存在损坏页,并定位到是由delete操作发现异常,因此修改subscriber_A上相应的复制存储过程;
之前采用的仅屏蔽掉IF部分的做法在此处并不适用,因为delete时的返回信息并不再是“影响0行记录”,而是由于页损坏导致记录无法找到并删除;
delete [dbo].[Order_A]where [Id] = @pkc1--if @@rowcount = 0-- if @@microsoftversion>0x07320000-- exec sp_MSreplraiserror 20598
此处为了方便后面定位可能出现的损坏页,修改存储过程如下:
先创建记录表monitor.dbo.tmp_byxl_Order_A_20140428
--CREATE TABLE monitor.dbo.tmp_byxl_Order_A_20140428 (id BIGINT,checkdate DATETIME DEFAULT GETDATE())--再修改存储过
新闻热点
疑难解答