目前在搜索引擎中搜索到的最常见的blog,是关于修复一个质疑的或者未恢复的数据库。解决这些问题的最好方式是使用你的备份,拥有一个备份策略,可以让你花最少的时间去恢复,并且没有数据丢失。但因为某种原因,你没有备份,怎么办?那么,取决于数据库里的什么损坏了且损坏何时被发现的。
当数据库损坏时,数据库处于3种状态:
1.ONLINE
1.如果数据库的一个数据文件损坏且在一个query中或者一些其他的操作中,这个损坏正好碰上,数据库将保持online且可以访问。
2.RECOVERY PENDING
1.如果SQL SERVER知道recovery要在数据库中运行但某些东东从一开始就阻止,数据库将处于这种状态。 这不同于SUSPECT,因为没说恢复会失败---只是没开始。
2.一个例子是当数据库没有正常的关闭(比如至少有一个未提交的活动事务时,数据库关了)且日志文件被删
3.SUSPECT
1.如果事务日志损坏,它将阻止恢复或者事务完全回滚,此时,数据库将处于这种状态。
2.一些例子:
* 当数据库没有正常关闭时,恢复努力去读损坏的数据页或者遇到一个损坏的日志记录。
* 一个通常的事务回滚,努力去读损坏的数据页或者遇到一个损坏的日志记录。
你可以在sys.databases目录视图里查看一个数据库的状态:
SELECT [state_desc] FROM [sys].[databases] WHERE [name] = N'数据库名';
GO
或者使用DATABASEPROPERTYEX函数:
SELECT DATABASEPROPERTYEX (N'数据库名', N'STATUS');
GO
请注意:当数据库是RECOVERY PENDING状态时,DATABASEPROPERTYEX返回SUSPECT,我将在下面演示。
因此数据库所处的状态决定你能做什么,如果你没有备份。最容易的情况是当数据库还处于ONLINE状态。在这种情况下,你可能运行repair消除损坏,最有可能的是一些数据丢失,然后采取步骤阻止损坏再次发生。如果repair不能修复所有的错误,在没有备份的情况下,你唯一的选择是提取尽可能多的数据到一个新的数据库里。
另外2种数据库状态是更困难的,使得人们去寻找帮助。在这种情况下,数据库根本不能访问,因为恢复没有运行或者完成,因此数据库处于不一致的状态。它可能是逻辑上的不一致(比如一个事务修改数据没有恢复)或者更糟糕它可能是结构上的不一致(比如一个系统事务修改索引关系没有恢复)。无论哪种方式,SQL Server想阻止你进入数据库,因为它不知道数据库的数据和结构处于什么状态。但是如果你没有备份,你需要进入数据库,不论事物处于什么样的状态。
你可以使用EMERGENCY模式。在SQL Server 2005中,sysadmin角色中的成员可以使数据库处于EMERGENCY状态中:
ALTER DATABASE [数据库名] SET EMERGENCY;
GO
一旦处于EMERGENCY状态,仅仅只有sysadmin角色中的成员可以访问数据库。数据库只读,什么都不能写入事务日志。
看看下面的例子:
CREATE DATABASE [emergencydemo];
GO
USE [emergencydemo];
GO
CREATE TABLE [salaries] (
[FirstName] CHAR (20),
[LastName] CHAR (20),
[Salary] INT);
GO
INSERT INTO [salaries] VALUES ('John', 'Williamson', 10000);
INSERT INTO [salaries] VALUES ('Stephen', 'Brown', 12000);
INSERT INTO [salaries] VALUES ('Jack', 'Bauer', 10000);
GO
我将开始一个显示的用户事务,更新表中的一行:
BEGIN TRANSACTION;
GO
UPDATE [salaries] SET [Salary] = 0 WHERE LastName = 'Brown';
GO
现在我将强制持有更新行的数据页写入磁盘:
CHECKPOINT;
GO
因此我们有了一个活动的,未提交的事务,就是更改了表,表的更改写入了磁盘。如果此时断电了,故障恢复将运行,事务将回滚。我将通过关闭SQL Server来模拟这个。在另外一个连接里:
SHUTDOWN WITH NOWAIT;
GO
使用登录名 rickcom\cjadcom 的 NOWAIT request 已将服务器关闭。
SQL Server 正在终止此进程。
我也将通过删除日志文件模拟损坏事务日志。
现在我再次启动SQL Server,我们可以在错误日志里看到下面的内容:
12/26/2013 14:59:06 spid19s Starting up database 'emergencydemo'.
12/26/2013 14:59:07 spid19s 错误: 17207,严重性: 16,状态: 1。
12/26/2013 14:59:07 spid19s FileMgr::StartLogFiles: Operating system error 2(系统找不到指定的文件。) occurred while creating or opening file 'D:\……\emergencydemo_log.LDF'. Diagnose and correct the operating system error, and retry the operation。
12/26/2013 14:59:07 spid19s 文件激活失败。物理文件名称'D:\……\emergencydemo_log.LDF'可能不正确。
12/26/2013 14:59:07 spid19s 无法重新生成日志。原因是数据库关闭时存在打开的事务/用户
数据库没有干净的关闭,事务日志不可用,因此恢复不能运行。最后的消息让人感兴趣--在SQL Server 2005中,有个特性,如果你附加或者打开一个数据库,没有事务日志文件,数据库是干净关闭的,SQL Server将自动产生一个新的日志文件。然而在我们这种情况下不能发生。
如果我尽力进入数据库会发生什么。
USE [emergencydemo];
GO
消息 945,级别 14,状态 2,第 1 行
由于文件不可访问,或者内存或磁盘空间不足,所以无法打开数据库 'emergencydemo'。有关详细信息,请参阅SQL Server 错误日志。
那么数据库处于什么状态?
SELECT DATABASEPROPERTYEX (N'emergencydemo', N'STATUS');
GO
返回SUSPECT。但是使用sys.databases表
SELECT [state_desc] FROM [sys].[databases] WHERE [name] = N'emergencydemo';
GO
返回RECOVERY PENDING。这是我前面预料的,恢复甚至没有机会开始。
现在我将数据库设为EMERGENCY模式,我可以进去看看里面的东东处于什么状态:
ALTER DATABASE [emergencydemo] SET EMERGENCY;
GO
当一个数据库被设为EMERGENCY模式后,你在错误日志里看到:
12/26/2013 16:07:52 spid53 Setting database option EMERGENCY to ON for database emergencydemo.
12/26/2013 16:07:52 spid53 Starting up database 'emergencydemo'.
12/26/2013 16:07:52 spid53 The database 'emergencydemo' is marked EMERGENCY_MODE and is in a state that does not allow recovery to be run.
我们再次试用数据库吧:
USE [emergencydemo];
GO
这次好了。数据是什么状态?
SELECT * FROM [salaries];
GO
FirstName LastName Salary
---------------------- ------------------------ --------------------
John Williamson 10000
Stephen Brown 0
Jack Bauer 10000
不一致,就像我预料的。
不对的地方请指正,谢谢!!
|
|