sqlserver检测到基于一致性的逻辑_数据页逻辑错误的检查及处理方法

前言:数据库越大,使用时间越长,貌似稳定性也在逐步下降。数据页逻辑错误,可能是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)的方式快速检测具体是哪个表有问题;

   此处的检测方法有局限性,初步分析如下:

  1.     如果是小表,可能在页损坏之前有类似操作,导致全部页还在缓存区中,因而select count(1)是可以获取结果的,无法判断出该表是否存页损坏;

  2.     如果IAM页中还有6:49413777的信息,且该页还在缓存区中,也是无法判断出该表是否存页损坏;

  3.     如果IAM页中没有6:49413777的信息,则select count(1)的时候会跳过已损坏的页,仍然可以获取结果,也是无法判断出该表是否存页损坏;

只有当IAM页中有6:49413777的信息,而该页又被交换出缓存区,需要进行物理读的时候,才会导致select count(1)无法获取结果,具体情况如下:

6009d3c6ef6df4f01d4cb2834a1e03ca.png

此处检测 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())--再修改存储过程INSERT INTO monitor.dbo.tmp_byxl_Order_A_20140428(id) VALUES(@pkc1)RETURN;--  delete [dbo].[Order_A]--where [Id] = @pkc1--if @@rowcount = 0--    if @@microsoftversion>0x07320000--        exec sp_MSreplraiserror 20598

  此处修改的目的:尽快跳过相应的删除操作,使Publisher_A的复制命令不致于积压的过多;

  对于update和insert操作也应进行相应的修改,否则将导致后续命令延迟;

5、考虑到DBCC checktable在执行修复时需要将数据库改为单用户模式,影响用户访问,因此不作为首选修复方案;

  由于subscriber_A是负载中的读库,因此首先将该服务器脱离负载环境,同时检查是否有通过IP直连数据库的应用,协调切串;

  如果直连的应用较多,短期内无法将连接串切走,可以先从上级分发重新复制一份不更名的表到subscriber_A,待数据同步后添加索引及相应的权限,再从Publisher_A上停止这个表的写入,摘除复制后交换subscriber_A的表名,重新搭建不初始化订阅的复制关系;这样可以在继续读取旧表大部分数据的同时完成新表的初始化工作,唯一受影响的除了磁盘空间外,还有初始过程中的IO开销;

  需要注意的是,如果publication中包含多个表,且上级发布服务器Publisher_A为SQLSERVER 2008 R2,则需要这个publication下所有的表都要重新初始化到新表;

  由于08 R2版本在删除article时会导致复制事务丢失的BUG,因此,只能按publication整体删除订阅,因此需要以publication为单位进行数据初始化;

  关于如何实现复制订阅端更名的表,可以看一下我之前的blog《Replication的犄角旮旯(一)--变更订阅端表名的应用场景》

6、继续对损坏页进行定位,一种方法是通过DBCC CHECKTA

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值