0

我有一个奇怪的问题。我有一个数据库,名为restorelogs.

自动备份脚本执行完整备份,之后每 3 小时进行一次差异备份。第二天再做一次完整的,然后再做一次差异,依此类推。

不,我想编写一个脚本,将这些文件还原到 restorelogs 数据库中。

从 php 我通过 sqlsrv 使用这些 sql 查询:

USE master;
ALTER DATABASE restorelogs SET MULTI_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307151435.bak' WITH REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307151745diff.bak' WITH FILE= 1, REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307152045diff.bak' WITH FILE= 1, REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307152345diff.bak' WITH FILE= 1, REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307160245diff.bak' WITH FILE= 1, REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307160545diff.bak' WITH FILE= 1, REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307160845diff.bak' WITH FILE= 1, REPLACE, NORECOVERY;
RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307161145diff.bak' WITH FILE= 1, REPLACE, RECOVERY;

现在将是游戏中有趣的部分。

如果我将这些查询复制到 SQL Server Management Studio 中并运行它,它就可以正常工作。有表格,没有错误消息,一切都很好。

但。当我尝试从 php 执行此操作时,数据库处于恢复模式。

当我阅读了很多页面时,我了解到,最后一个查询需要包含RECOVERY恢复数据库的选项(我也尝试不使用 REPLACE,就在第一个查询中)。

怎么会发生?

请帮助我,我做错了什么。

更新:基于亚当的评论:我确实尝试这样做。我收集备份文件,并使用第一个(完整)、NORECOVERY、REPLACE 和最后一个 WITH RECOVERY。

这就是我尝试的方法: function pushToDatabase($files) {

$dbh = new Database();
$dbh->query("USE master");
pre($dbh->errorInfo(), 0);
$cnt = count($files);
$i = 0;
foreach ($files as $file) {
    $withFile = '';
    $option = '';
    $moves = '';
    if ($i == 0) {
    //restoreFromDisk($file);
    //truncateDatabase();
    $option = " NORECOVERY, REPLACE";
    } else {
    $option = " RECOVERY";
    }
    if ($i > 0) {
    $withFile = " FILE=1, ";
    }
    if ($i == 0 || $i == count($files) - 1) {
    $sql = "RESTORE DATABASE " . DB_NAME . " FROM DISK = '" . $file . "' WITH  " . $withFile . $option . ";";
    echo $sql . "<br />";
    $dbh->exec($sql);
    pre($dbh->errorInfo(), 0);
    }
    $i++;
}
$sql = "RESTORE DATABASE " . DB_NAME . " WITH RECOVERY;";
$dbh->exec($sql);
pre($dbh->errorInfo(), 0);
echo $sql . "<br />";
die("NOW WE ARE DONE!");
}

第一条语句运行没有任何问题:

RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307151435.bak' WITH NORECOVERY, REPLACE;

但在此之后,当我想恢复最后一个差异文件时:

RESTORE DATABASE restorelogs FROM DISK = 'D:/Apache/htdocs/logreader/extracts/SRO_VT_LOG201307161145diff.bak' WITH FILE=1, RECOVERY;

我收到一条错误消息:

[Microsoft][SQL Server Native Client 10.0][SQL Server]A previous restore operation was interrupted and did not complete processing on file 'Log_DB_Data'. Either restore the backup set that was interrupted or restart the restore sequence.'

并且数据库状态处于恢复模式。

我也尝试过使用 RESTORE FILELISTONLY,并将文件移动到正确的位置。我可以这样做,但在那之后我无法恢复差异备份。

function restoreFromDisk($file) {
    $sql = "RESTORE FILELISTONLY FROM DISK = '" . $file . "'";
    $res = dbQuery($sql);
    $option = ' ,REPLACE, RECOVERY';
    while ($row = dbFetchAssoc($res)) {
    if ($row["LogicalName"] == "Log_DB_Data") {
        $move[] = " MOVE '" . $row["LogicalName"] . "' TO '" . MSSQL_DATA_PATH . "resetlogs.mdf'";
    } else {
        $move[] = " MOVE '" . $row["LogicalName"] . "' TO '" . MSSQL_DATA_PATH . "resetlogs.ldf'";
    }
    }
    $moves = join(",", $move);
    $sql = "RESTORE DATABASE " . DB_NAME . " FROM DISK = '" . $file . "' WITH  " . $moves . $option . ";";
    dbQuery($sql);
    echo $sql . "<br />";
    $sql = "RESTORE DATABASE " . DB_NAME . " WITH RECOVERY;";
    dbQuery($sql);
    echo $sql . "<br />";
}
4

2 回答 2

0

如果有可能连接用户(并且如果可以终止他们的会话),您应该将数据库设置为单用户。既然你正在恢复数据库,我认为没关系。您将需要在完整备份还原上指定替换选项。此外,您只需还原最新的差异备份(与恢复一起使用),因为它将包含自上次完整备份以来的所有更改。还应注意,此还原将不包括自上次差异备份以来发生的事务。

我会考虑每 3 小时使用一次日志备份。这将对您的系统产生较小的影响,并允许日志截断(如果您处于完全恢复状态)。在此还原方案中,您将需要完整备份和所有日志备份,最后一个选项指定恢复。

于 2013-07-24T20:45:49.110 回答
0

另一种方法是将您的 SQL 脚本写入临时文件,然后使用 osql 将其作为脚本执行。当然,这假设您在安装了 osql 的机器上运行。

osql -E -S <server> -d master -i <sql file>
于 2013-09-27T18:26:40.533 回答