咨询热线:4006-75-4006
售前:9:00-23:30 备案:9:00-18:00 技术:7*24h
在经历了上面的文件级别错误后,在数据库启动的过程,还经常出现的是数据页级别的错误,相对于上面的文件错误级别,在数据页中造成的错误粒度更小,并且基本不会反映到数据库级别,也就是说在出现数据页级别的错误时候,该数据时可以正常访问的,只是在访问有错误的数据页的时候才会报错,在我们遇到这种错误的时候该如何解决呢?
下面我们依次来分析,首先我们来制作一个经典的824错误,以下部分内容牵扯到数据库部分基础,限于篇幅,我们不做详细介绍:
<1>首先我们在我们的测试库中新建一个表,我们将该表新建成一行为一个数据页的方式,也就是说一行数据库在数据库中就能承载一个数据页
USE CnblogsTestDB GO CREATE TABLE [dbo].[TestPage] ( [a] [int] NULL, [b] [nvarchar](3900) NULL ) ON [PRIMARY]
脚本很简单,一张表,两列,一列int类型,一列nvarchar(3900),一行数据的存储空间为:3900*2(nvarchar(3900))字节+4(int)+96字节(页头)+36字节(行偏移)=7932字节,我们知道一个数据页存储的信息为8K=8192字节,包括其它消耗所以该表一行数据如果填充完,一行数据将近乎占据一个数据页。
我们来添加三行数据,然后查看页信息:
--插入三条数据 insert [TestPage] values(1,REPLICATE('A',3900)) insert [TestPage] values(2,REPLICATE('B',3900)) insert [TestPage] values(3,REPLICATE('C',3900)) go--查看页信息 dbcc traceon(3604)--查看库中页集合 dbcc extentinfo(CnblogsTestDB,[TestPage])
可以看到,该表中现在有三个数据页,我们来看看数据页应该也是近乎沾满的
上图显示了,通过扫描表信息,共含有3个数据页,每个数据页中的数据量存储占比到了96.55%,也就是说基本上是填充满了。
当然,我们还可以通过DBCC PAGE命令,来查看每个页中的具体内容,我们简单的看一个页面编号为90的数据页:
通过上面的命令可以看到,该数据页中存储的为表中的第一行的数据,并且在数据库存储文件中是以十六进制方式编码存储。
当然,如果感觉此方式不直观,可以利用一个小工具进行数据页的查看,这里我推荐使?Internal Views(此工具在桦仔的博文中有详细介绍),可更直观的展示数据存储页信息:
这里我们可以点击我上面上面查看的第一行的数据内容页进行查看
经过上面的分析步骤,其实我的目的是想重现在SQL Server启动过程中,或者在线上的数据库经常遇到的经典错误824错误
上述过程是原理篇,因为我们必须知道数据存储的底层原理,才能理解好这个错误的原因,以及找到正确的处理方法。
下一步,我们来重现这个错误的原因,我们知道在我新建的测试表中含有两个字段:a和b,并且a为int类型、b为nvarchar类型
然后我们介绍了底层的存储机制,我现在将第一列a字段的整形数据内容存储改成字符串类型,依次来损坏掉该数据页内容
我先将服务停掉,然后用文件编辑工具,修改此数据页内容,该数据页内容为十六进制内容,当然在我搞坏这部分数据页之前我先做一个完整备份
然后修改该数据页信息,这里我使用UltraEdit文本编辑工具,打开文件,找到该数据页内容
我们将上面的源数据更该一下,来把这个数据页损坏掉
我们保存,然后重新启动该数据库看看
这就是我们平常比较常见的824错误的过程,而此过程有可能是磁盘坏道造成,或者误修改文件等诸多原因,但是此问题还是比较常见的
当然,这种数据页面的损坏可能造成的影响不是库级别的,也就说不会造成数据库不能访问,其它表是能正常访问的,但是只是在操作此损坏的数据页的时候才会报错,但有时候这几个数据页的损坏对业务产生的影响有可能就是致命的,所以我们要解决掉。
郑重提示:上面过程也可以正确的更改数据页中的数据,但是如果没有确切的把握,基本上能把数据库搞瘫痪掉,我是为了重现问题才修改底层元数据,所以在自己的生产库中千万不要乱搞!
在数据库启动的过程中,会发生一致性校验,所以该错误应该会记录到Error的错误日志文件中,我们来看:
windows平台下的错误日志:
当然,在启动的过程中该问题有可能发生很多,比如磁盘坏道等原因,一系列的数据页可能就没法访问了。所以SQL Server会将这些损坏的页面记录到msdb系统库中,这我们在这个库中查找到损坏的页面集合:
至此,我们已经重现了经典的824错误,那我们该如何解决此问题呢?
解决方法:
a、如果此问题出现的页面为数据承载页,也就说该页存储的为内容数据或者为聚集索引的叶子节点数据,并且存在镜像,版本在SQL Server2005以上,那么这个错误基本可以忽略,SQL Server能够自动帮你修复此错误。
b、如果此问题出现在没有镜像的环境中,那就要区分是损坏页面是否为聚集索引叶子节点数据,如果是,那就简单了,直接重建索引就好了,如果不是,那此种方案还是不能解?,判断方法如下:
利用DBCC PAGE命令查看当前数据页内容,根据ObjectId跟踪该页位于哪个对象上,Metdata:IndexID的值判断是否为索引树中的节点值,如果大于0则表示为索引值,此时,重建该索引既可以。比如:
我们根据该页的ObjectID,从数据库中查找该页所属对象。
c、如果上述方案都不能满足,那只有采取此种方案,我们可以利用数据库备份进行还原,当然为了最大限度的避免数据库离线,我们最好采取数据页还原的方式,此种方式最为简单,还原速度也最快,能够最大限度的缩短数据库离线时间,并且保证数据完整性。
这里提示下:在SQL Server2012版本一下,SSMS不提供图像化数据页还原方式,在SQL Sever以后的版本中,有图像化界面操作。
所以,我们只能通过如下脚本进行还原:
RESTORE DATABASE CnblogsTestDB PAGE='1:90'FROM DISK = N'F:SQLTestCnlogsTestDB.bak'WITH NORECOVERY
当然有事务日志、更新备份的,需要依次恢复这过程的所有的备份,不要忘记备份尾部日志。
但是此方法也有局限性:
如果损坏的数据页为
1、分配页:GAM、SGAM和PFS页
2、所有数据文件的启动页
如果发生损坏的是以上两种,则无法通过该备份恢复页方式进行恢复。如果这种情况下,建议考虑找合适的时间段进行全库的恢复操作。(推荐)
d、上述情况是在存在有备份的情况下,如果没有数据库备份,那我们只能选择最后的一招了,那就是DBCC CHECKDB命令,同样和上面一样,此种方式可能会造成数据丢失,所以不建议采用,如果能容忍数据丢失,采用的过程参照文中的上半部分。(不推荐)
至此,我们已经完成了一个SQL Server启动过程或者平常最经常遇到的一个经典错误824错误,我们来总结下:
824错误原因:大部分是由于磁盘存储导致的数据页损坏,导致的SQL Server在读取的时候发生了错误。
导致错误场景:磁盘坏道、突然断电等情况下经常会出现此错误。
----------------------------------------------------------霸气的分割线-----------------------------------------------------------------------
和824错误相关的还有一种是823错误,我们来介绍下该错误信息
由于场景所限,我就不重现该错误了,在这里我详细的介绍下这两种错误的原因和原理,就可以了,如果遇到了,解决的方式基本都是一致的,可参照上面的824错误解决方法。
SQL Server在每次写入页面的时候,会根据页面里的数据算出一个校验值?一同存储到页面中去。当下次读取页面的时候,再根据这次读到的页面数据,算出一个新的校验值。如果写入和读出的数据一模一样,那么两个校验值就是相等的。如果两个校验值不相等,就意味着上次SQL Server写入的数据和这次读取出来的一定不同,现在读取出来的数据就有问题了。
823错误就代表着SQL Server在向操作系统申请某个页面读写的时候遇到了Windows?取或写入请求失败。所以该问题的原因大部分是源自于操作系统层面,更确切的说是物理文件损坏而导致此错误,比如设备驱动程序导致等。
824错误则是在读取数据页面时候,发现数据页面有问题,比如读取出来的校验值不对等。
当上面描述的823和824错误出现大面积的时候,或者直接部分数据文件完全坏掉的情况下,在SQL Server启动过程中就会出现数据库SUSPECT“质疑”状态。
经过我的多次数据页的破坏和摧残,我已经顺利的将我们的这个测试库给搞成?质疑状态,我们来看SUSPECT(质疑)的状态库:
这里我直接DBCC CHECKDB命令尝试着恢复下看看
所以到此,我们要做的就是避免上述错误的发生。如果在生产库中?生了我上面的情况,然后没有数据库备份,那么剩下来你要做的事情:我估计就是准备简历了.....
结语
文章主要还是分析SQL Server启动过程中,加载用户数据库的时候,所遇到的一系列问题,文中部分内容需要有一定数据库基础知识才能读懂,篇幅有限,我们没有做深入的讲解分析,比如上面的几个重要的命令DBCC PAGE....DBCC CHECKDB..等等,随便一个都能写出一系列的内容,我们侧重的还是问题的解决,和问题原因分析,后续文章中会介绍这一系列的命令作用,以及正确的使用技巧。
文中部分数据库错误都是我耗费精力一步一步调整出来,目的是真实的展现错误明细,其实问题解决容易,问题重现的过程复杂。
如果经常使用SQL Server,其实这些问题都是我们会经常遇到的,所以我们要记住相应的解决方案,做的有备无患!