数据库页已标记为 RestorePending,可能表明磁盘已损坏。要从此状态恢复,请执行还原操作。

图片 12

 解决办法:

在设置多用户模式的时候可能会因为还有其它进程的连接导致设置无法进行,所以需要杀掉所有连接的进程。

方式一

USE master;   
GO   
DECLARE @SQL VARCHAR(3000);  
SET @SQL = '';  
SELECT @SQL = @SQL+'; KILL ' + RTRIM(SPID)  
FROM [sys].[sysprocesses] AS sps  
WHERE [sps].[dbid] = DB_ID('test');   
SET @SQL = SUBSTRING(@SQL, 2, LEN(@SQL));  
EXEC(@SQL);  
GO  

方式二

DECLARE @DBName SYSNAME;  
SET @DBName = 'BI_Monitor'; --这个是要删除的数据库库名      

DECLARE @KSQL NVARCHAR(1000)  
DECLARE tb CURSOR LOCAL  
FOR    
SELECT  
    KSQL = 'KILL ' + CAST([sps].[spid] AS NVARCHAR(10))  
FROM [sys].[sysprocesses] AS sps  
WHERE dbid = DB_ID(@DBName)--查询@DBName相关的线程  

--循环杀掉要删除数据的相关线程  
OPEN tb  
FETCH NEXT FROM tb INTO @KSQL  
WHILE @@FETCH_STATUS = 0    
BEGIN    
    EXECUTE(@KSQL);  
    FETCH NEXT FROM tb INTO @KSQL  
END   
CLOSE tb      
DEALLOCATE tb  

最后再将相应数据库设置为多用户模式即可。

ALTER DATABASE [test] SET MULTI_USER;--设置为多用户模式  

 

数据库修复

--修复改数据库 1.此时我们需要将数据库设置成单用户模式:
右键点击数据库 -> 属性 -> 选项 -> 状态 -> 限制访问 -> 选择Single-> 确定。注意修复完成后需要改回多用户模式。
--2.使用dbcc checkdb进行数据库修复
DBCC CHECKDB ('db_xfzx', REPAIR_FAST) 
--修复过程中报错信息:
T_JXJS_HYJL的 DBCC 结果。
消息 8928,级别 16,状态 2,第 1 行
对象 ID 885578193,索引 ID 1,分区 ID 72057594060341248,分配单元 ID 72057594075873280 (类型为 In-row data): 无法处理页 (1:70890)。有关详细信息,请参阅其他错误消息。
        DBCC 语句的修复级别导致避开了此修复。
消息 8939,级别 16,状态 98,第 1 行
表错误: 对象 ID 885578193,索引 ID 1,分区 ID 72057594060341248,分配单元 ID 72057594075873280 (类型为 In-row data),页 (1:70890)。测试(IS_OFF (BUF_IOERR, pBUF->bstat))失败。值为 12584969 和 -6。
        修复此错误要求首先修正其他错误。
消息 8976,级别 16,状态 1,第 1 行
表错误: 对象 ID 885578193,索引 ID 1,分区 ID 72057594060341248,分配单元 ID 72057594075873280 (类型为 In-row data)。在扫描过程中未发现页 (1:70890),但该页的父级 (1:704) 和上一页 (1:450709) 都引用了它。请检查以前的错误消息。
        修复此错误要求首先修正其他错误。
对象 'T_JXJS_HYJL' 的 6 页中有 249 行。
CHECKDB 在表 'T_JXJS_HYJL' (对象 ID 885578193)中发现 0 个分配错误和 3 个一致性错误。
​
--3.重建索引并修复,报一样的错
DBCC CHECKDB ('db_xfzx', REPAIR_REBUILD)
​
--4.在修复过程中发现T_YWGY_WSQD_WS,T_JXJS_HYJL均有此报错。同时检查其他库没有发现有损坏情况。
​
--5.尝试进行单个表修复,以及对损坏页的单独修复,均会报上面的的错。
dbcc checktable('t_jxjs_pctq',REPAIR_REBUILD) 
dbcc page(11,1,60682,3)

dbcc checkdb并未能解决问题。

 

 


问题背景

运维操作失误,在没有正常关闭sqlserver的情况下,将服务器关闭了,重启后某些表损坏(应该是某些页损坏了,没有损坏的页还能访问到数据,但是访问损坏了的页就有问题),目前数据库只有4.20号的备份。

图片 1

解决办法:

快速修复
DBCC CHECKDB ('数据库名', REPAIR_FAST) 

重建索引并修复
DBCC CHECKDB ('数据库名', REPAIR_REBUILD)

如果必要允许丢失数据修复
DBCC CHECKDB ('数据库名'', REPAIR_ALLOW_DATA_LOSS)

重建索引

1.执行了dbcc
checkdb后,报错的信息里有索引 ID
1;这个信息的提供,可能是索引页的损坏。但是前面执行的DBCC CHECKDB
(‘db_xfzx’, REPAIR_REBUILD)重建索引修复,并没能解决问题。

2.猜测:因为一个表中有多个索引,所以是不是单独重新生成每一个索引就能发现是哪个索引有问题呢?

3.在sqlserver客户端工具上面,对表T_JXJS_HYJL包括主键在内的三个索引进行重新生成,过程中有一个普通索引(I_JXJS_PCTQ_TQXX)的重新生成失败了,报错信息和最开始查询的信息一样。尝试重新组织该索引还是一样的问题。那么问题就出在I_JXJS_PCTQ_TQXX这个普通索引上了。

4.既然重建索引失败了,尝试删除该索引,发现可以删除,再重新创建该索引。

5.重建完成后再修复,DBCC CHECKDB
(‘db_xfzx’, REPAIR_FAST)
。这时异常信息里面没有T_JXJS_HYJL表的异常信息。查看表中的数据已经正常,异常的数据可以正常查询,数据量的统计也已经正常。

6.同样T_YWGY_WSQD_WS该表有一个普通索引重新生成有问题,采用上面的方法也能解决。而T_JXJS_HYJL这张表的数据出现重建异常的是主键,由于有主键约束,所以不能删除索引,尝试修改为非主键,但是报错和查询一样的的错误。看来主键的数据不能这么做。最终由于该表只有两百多条数据,而且并不重要,直接恢复了4.20号的数据。

7.当然对表T_YWGY_WSQD_WS也可以采用将该表的数据通过select
* into tableA from
tableB;的形式插入到另外的表,重新创建该表后将数据恢复回来,然后重建索引。

….此篇耗时四天完成….文中部分数据库错误都是我耗费精力一步一步调整出来,目的是真实的展现错误明细,其实问题解决容易,问题重现的过程复杂。

错误提示:

当我们修复完数据库后,需要将其恢复为多用户模式,此时可能出现

数据库 'xxx' 已打开,并且一次只能有一个用户访问

报错信息

查询脚本:select * from
t_jxjs_pctq where c_bh_tqxx =
‘8ae480b26320550e016323d098050175’;

报错信息:HY000-[SQL Server] 数据库
ID
11,页[1:60682]已标记为RestorePending,可能表名磁盘已损坏,要从此状态进行恢复,请执行还原操作。

而且,相对于侧重面而言,其实我们更关注的是我们自己建立的用户数据库,假如系统数据库出现问题,甚至实例出现问题,最坏的情况我们重搭环境,但是如果我们应用的用户数据库坏掉了,那可不是重搭环境就能解决的。这牵扯到公司利益问题,问题严重性不言而喻!

错误提示:

执行修复命令时,可能会出现以下错误:

未处理修复语句。数据库需处于单用户模式下解决

报错可能的原因

RestorePending一般是在进行页恢复的过程中出现的,就是在进行了restore操作之后但还没有进行recovery操作之前页的状态。出现这样的问题可以肯定这个表是损坏了,但是在查询数据的时候如果不会查询到损坏页面的数据话是不会报错的,也就是说可以有条件的使用这个表。参考资料

当然,在启动的过程中该问题有可能发生很多,比如磁盘坏道等原因,一系列的数据页可能就没法访问了。所以SQL
Server会将这些损坏的页面记录到msdb系统库中,这我们在这个库中查找到损坏的页面集合:

错误提示:

消息 829,级别 21,状态 1,第 1 行
数据库 ID 15,页 (1:21826) 已标记为 RestorePending,可能表明磁盘已损坏。要从此状态恢复,请执行还原操作。

5.7号和4.20号的数据量对比

表名 4.20号 5.6号
T_JXJS_PCTQ 1716 2175
T_YWGY_WSQD_WS 7358 8275
T_JXJS_HYJL 244 287

图片 2

 

结语

1.运行dbcc
checkdb(db_name)检查数据库的完整性。根据日志判断可能由于某个索引的索引页缺失,索引不完整,导致某些数据查询的异常。而重新生成索引,不能成功,可以先删除该索引,再重新创建。

2.如果是主键索引则可以采用数据迁移的方式。

3.需要注意的是修复过程中不要使用DBCC
CHECKDB (‘数据名”,
REPAIR_ALLOW_DATA_LOSS),REPAIR_ALLOW_DATA_LOSS该语句是可能丢失数据的。

4.修复完成后需要从单用户模式修改为多用户模式。

5.做到未雨绸缪,提前做好备份,每天备份,对备份的数据进行还原测试。做到有”备”无患

 

 

823错误就代表着SQL
Server在向操作系统申请某个页面读写的时候遇到了Windows读取或写入请求失败。所以该问题的原因大部分是源自于操作系统层面,更确切的说是物理文件损坏而导致此错误,比如设备驱动程序导致等。

引起原因:

RestorePending一般是在进行页恢复的过程中出现的,就是在进行了restore操作之后但还没有进行recovery操作之前页的状态。

出现这样的问题可以肯定这个表是损坏了,但是在查询数据的时候如果不会查询到损坏页面的数据话是不会报错的,也就是说可以有条件的使用这个表。

如果损坏的页只有一个的话,那删除掉这个坏表故障肯定就没有了,因为一个页里面只会放一个表的数据。

损坏的直接原因就是放在磁盘上面的数据被意外的修改了或者写入的时候出错这些,可能是磁盘问题,但是IO系统可能性更大。

可以好好的检查系统日志和SQLServer的LOG,看看里面有没有关于磁盘或者IO之类的警告、报错信息,以进一步确定原因。

至于处理方法,如果表重要那就利用备份做页面还原恢复数据,不重要的话就删掉重建,

或者使用以下方式进行修复,在处理完坏页之后再对整个数据库做一次DBCC
CHECKDB操作,确保没有其他的坏页。

上述过程是原理篇,因为我们必须知道数据存储的底层原理,才能理解好这个错误的原因,以及找到正确的处理方法。

解决办法:

此时我们需要将数据库设置成单用户模式:

右键点击数据库 -> 属性 -> 选项 -> 状态 -> 限制访问 -> 选择Single-> 确定。

 图片 3

 

图片 4

前言

郑重提示:上面过程也可以正确的更改数据页中的数据,但是如果没有确切的把握,基本上能把数据库搞瘫痪掉,我是为了重现问题才修改底层元数据,所以在自己的生产库中千万不要乱搞!

  2、所有数据文件的启动页

上面的情况是找到数据库文件,但是不能打开数据库文件,当然还有可能是直接找不到数据库文件,系统会报出如下错误:

当然,在恢复完成之后,不要忘记将数据库改回多用户模式

出现这个状态通常的原因是数据库文件找不到,或者文件找到权限访问不到,我们来看该问题报错信息:

  1、分配页:GAM、SGAM和PFS页

 

图片 5

图片 6

错误信息很明显,说这个该文件不能访问,并且确切的说出了这个为操作系统错误,那我们看操作系统的错误记录:

RESTORE DATABASE CnblogsTestDB
PAGE='1:90'
FROM DISK = N'F:SQLTestCnlogsTestDB.bak'
WITH NORECOVERY

如果您看了本篇博客,觉得对您有所收获,请不要吝啬您的“推荐”。

和824错误相关的还有一种是823错误,我们来介绍下该错误信息
由于场景所限,我就不重现该错误了,在这里我详细的介绍下这两种错误的原因和原理,就可以了,如果遇到了,解决的方式基本都是一致的,可参照上面的824错误解决方法。

然后我们介绍了底层的存储机制,我现在将第一列a字段的整形数据内容存储改成字符串类型,依次来损坏掉该数据页内容

上述解决方案中CHECKDB命令,是一种万不得已的方式,而且,我可以明确的告诉你这命令使用的时候会可能造成数据丢失,并且在大数据库中,运行周期很长!

当然个人能力有限,部分不当之处,还望指出不吝赐教。

这个状态表示数据在启动完成后,正在发生恢复,也就是上面日志中的
Recovery过程,和其它的关系型数据库一样,SQL
Server对所有的数据库行为都是先写事务日志,然后在修改内存中的数据,然后通过后台的一个进程在适当的时候进行写入硬盘(Lazy
write),所以在数据库运行过程中,磁盘中的数据并不是最新的,如果这个时候关闭了,在下一次启动过程中SQL
Server就要根据事务日志中的记录,将磁盘中的旧的数据改写,改写过程为:

OFFLINE(离线):有在线状态就有离线状态,很简单,让数据库离线,用户不能使用

结语

b、不能找到文件了,那就得只能删除该库,重新新建同名库,从备份文件中还原

当上面描述的823和824错误出现大面积的时候,或者直接部分数据文件完全坏掉的情况下,在SQL
Server启动过程中就会出现数据库SUSPECT“质疑”状态。

经过我的多次数据页的破坏和摧残,我已经顺利的将我们的这个测试库给搞成了质疑状态,我们来看SUSPECT(质疑)的状态库:

这个状态应该是最期待的了,数据库在线,正常使用,默认都是正常的在线状态。

 图片 7

我们将上面的源数据更该一下,来把这个数据页损坏掉

当我们处于生产环境中,生产库不能正常启动的时候,此刻的火烧眉毛的时刻,采取上面的方法先确保一部分数据能正常访问也不失为一种缓议之计。

ONLINE(在线):

图片 8

图片 9

利用DBCC
PAGE命令查看当前数据页内容,根据ObjectId跟踪该页位于哪个对象上,Metdata:IndexID的值判断是否为索引树中的节点值,如果大于0则表示为索引值,此时,重建该索引既可以。比如:

文章最后给出本篇的关联篇:

然后修改该数据页信息,这里我使用UltraEdit文本编辑工具,打开文件,找到该数据页内容

我们根据该页的ObjectID,从数据库中查找该页所属对象。

其实从市面上的所有数据库而言,其本身所有的机制都是通过先写日志,然后通过一个进程后写入(lazy
write)方式写入到磁盘,这种方式是为了避免IO的阻塞,因为我们都知道磁盘IO这个问题一直是所有文件读写的最大瓶颈。

在数据库启动的过程中,会发生一致性校验,所以该错误应该会记录到Error的错误日志文件中,我们来看:

 

这里我直接DBCC CHECKDB命令尝试着恢复下看看

如果经常使用SQL
Server,其实这些问题都是我们会经常遇到的,所以我们要记住相应的解决方案,做的有备无患!

DBCC CHECKDB(CnblogsTestDB,REPAIR_ALLOW_DATA_LOSS)
GO

我们先来看数据库模式为简单(SIMPLE)模式的,我将咱们的测试库设置成简单模式:

d、上述情况是在存在有备份的情况下,如果没有数据库备份,那我们只能选择最后的一招了,那就是DBCC
CHECKDB命令,同样和上面一样,此种方式可能会造成数据丢失,所以不建议采用,如果能容忍数据丢失,采用的过程参照文中的上半部分。(不推荐)

下一步,我们来重现这个错误的原因,我们知道在我新建的测试表中含有两个字段:a和b,并且a为int类型、b为nvarchar类型

RECOVERY PENDING(挂起还原)

a、如果此问题出现的页面为数据承载页,也就说该页存储的为内容数据或者为聚集索引的叶子节点数据,并且存在镜像,版本在SQL
Server2005以上,那么这个错误基本可以忽略,SQL
Server能够自动帮你修复此错误。

图片 10

我们先将数据库设置成EMERGENCY(紧急)模式,并且为单用户(SINGLE_USER)模式

图片 11

脚本很简单,一张表,两列,一列int类型,一列nvarchar(3900),一行数据的存储空间为:3900*2(nvarchar(3900))字节+4(int)+96字节(页头)+36字节(行偏移)=7932字节,我们知道一个数据页存储的信息为8K=8192字节,包括其它消耗所以该表一行数据如果填充完,一行数据将近乎占据一个数据页。

至此,我们已经重现了经典的824错误,那我们该如何解决此问题呢? 

图片 12

在经历了上面的文件级别错误后,在数据库启动的过程,还经常出现的是数据页级别的错误,相对于上面的文件错误级别,在数据页中造成的错误粒度更小,并且基本不会反映到数据库级别,也就是说在出现数据页级别的错误时候,该数据时可以正常访问的,只是在访问有错误的数据页的时候才会报错,在我们遇到这种错误的时候该如何解决呢?

当经历了上面的这个几个状态都不出现问题,上面的这几个状态下,数据库都是不能使用的,会进入到下面这个状态:

 

当然,这种数据页面的损坏可能造成的影响不是库级别的,也就说不会造成数据库不能访问,其它表是能正常访问的,但是只是在操作此损坏的数据页的时候才会报错,但有时候这几个数据页的损坏对业务产生的影响有可能就是致命的,所以我们要解决掉。

EMERGENCY(紧急):这个状态也是管理员用的,就是说明数据库有问题了,它正在尽量解决

上面的出现问题的文件为数据库的主文件组,当我们数据库在承载到一定数据量的情况下,我么采取多个辅助文件组来容纳数据,下面我们来看一下辅助文件组的问题:

而这过程中会发生很多问题,在分析问题之前,我先要介绍SQL
Server数据库的几个常见状态:

 c、如果上述方案都不能满足,那只有采取此种方案,我们可以利用数据库备份进行还原,当然为了最大限度的避免数据库离线,我们最好采取数据页还原的方式,此种方式最为简单,还原速度也最快,能够最大限度的缩短数据库离线时间,并且保证数据完整性。

2、回滚和撤销 undo/rollback

USE CnblogsTestDB
GO
ALTER DATABASE CnblogsTestDB SET EMERGENCY
GO
ALTER DATABASE CnblogsTestDB SET SINGLE_USER
GO
You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图