Joh*_*eng 2 sql-server sql-server-2008-r2
我移动了我的数据库文件。当我自己去附加 MDF 文件时,SQL Server 会告诉我它找不到日志文件。在附加之前,我如何询问 MDF 需要哪些文件?
更多背景信息:我有一堆 SAN 备份卷。我通过 iSCSI 将它们连接到 Windows,现在一半的驱动器号都搞砸了。而且,我应该将多个卷映射到保存驱动器号,所以我无法恢复正确的驱动器号。
我知道文件都在那里,但我不知道我应该为每个 MDF 附加多少和哪些 LDF/NDF。
如果您拥有backupset
表中所有备份的信息,您可以通过RESTORE FILELISTONLY
这种方式构建所有命令,然后将结果插入 #temp 表中,然后使用游标构建最终CREATE DATABASE ... FOR ATTACH
命令。我仍然认为吸收它并已经恢复备份会更快,但我想每个人都是他自己的......
首先,创建一个 #temp 表来保存RESTORE FILELISTONLY
输出:
SET NOCOUNT ON;
CREATE TABLE #x
(
ln SYSNAME, [path] NVARCHAR(512), Type CHAR(1), fgn NVARCHAR(128),
size BIGINT, msize BIGINT, FileId INT, lsn1 BIGINT, lsn2 BIGINT,
id UNIQUEIDENTIFIER, lsn3 BIGINT, lsn4 BIGINT, bsize BIGINT, bs INT,
fg INT, lgid UNIQUEIDENTIFIER, lsn5 BIGINT, bid UNIQUEIDENTIFIER,
ro BIT, p BIT, TDEThumbprint VARBINARY(32)
);
Run Code Online (Sandbox Code Playgroud)
现在,根据存储在 中的备份msdb..backupset
,自己生成命令并运行它们:
DECLARE @sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY database_name
ORDER BY backup_start_date DESC)
FROM msdb..backupset
)
SELECT @sql += '
INSERT #x(ln) SELECT ''' + x.database_name + ''';
INSERT #x EXEC sp_executesql N''RESTORE FILELISTONLY '
+ ' FROM DISK = ''''' + mf.physical_device_name + ''''''
+ ' WITH FILE = ' + RTRIM(x.position) + ';'';'
FROM x
INNER JOIN msdb..backupmediaset AS ms
ON x.media_set_id = ms.media_set_id
INNER JOIN msdb..backupmediafamily AS mf
ON ms.media_set_id = mf.media_set_id
WHERE x.rn = 1;
EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)
现在,如果.bak
文件已被移动,其中一些可能会失败。另请注意,该position
值很重要,以防您多次备份到同一文件。您想确保您拥有反映数据库当前文件结构的最新版本(但仍不能保证上次备份反映真实情况)。
现在,添加一列作为行号。警告:这依赖于堆的“自然”排序顺序。如果这个表超大,这可能不起作用。
ALTER TABLE #x ADD rn INT;
GO
;WITH x AS (SELECT *, r = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM #x)
UPDATE x SET rn = r
OPTION (MAXDOP 1);
GO
Run Code Online (Sandbox Code Playgroud)
一旦在那里有了路径,您将看到它们反映了数据库文件的旧位置和驱动器号。您可能希望运行一个查询,用新位置替换已知的旧位置。例如,如果您知道之前位于 的数据库C:\MSSQL\Data\
不位于D:\MyInstance\SQLData\
,则可以运行:
UPDATE #x SET [path] = REPLACE([path], 'C:\MSSQLData\', 'D:\MyInstance\SQLData\')
WHERE [path] LIKE 'C:\MSSQLData\%';
Run Code Online (Sandbox Code Playgroud)
清洗、冲洗、重复直到所有[path]
值准确反映文件的新位置。
现在,我们已经准备好卷起袖子了。这很可能是一种不好的做法,按照我说的做,但不像我发布的那样做。我们需要一个游标来构建CREATE DATABASE ... FOR ATTACH
命令。下面的游标依赖于rn
我们添加的列并构建了准确处理多个数据文件、多个日志文件或两者的命令。
DECLARE @ln SYSNAME, @rn INT, @ubound INT, @cmd NVARCHAR(MAX);
DECLARE c CURSOR LOCAL FAST_FORWARD
FOR SELECT ln, rn FROM #x WHERE [path] IS NULL;
OPEN c;
FETCH NEXT FROM c INTO @ln, @rn;
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @ubound = MIN(rn) FROM #x WHERE [path] IS NULL AND rn > @rn;
SET @ubound = COALESCE(@ubound, 2000000000);
SELECT @cmd = N'CREATE DATABASE ' + QUOTENAME(@ln) + '
ON '
+ STUFF((SELECT ',' + '(NAME = ''' + ln + ''',FILENAME='''
+ [path] + ''')' FROM #x WHERE rn > @rn AND rn < @ubound
AND [Type] = 'D' ORDER BY FileId
FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)'),1,1,'')
+ '
LOG ON
' + STUFF((SELECT ',' + '(NAME = ''' + ln + ''',FILENAME='''
+ [path] + ''')' FROM #x WHERE rn > @rn AND rn < @ubound
AND [Type] = 'L' ORDER BY FileId
FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)'),1,1,'')
+ '
FOR ATTACH;';
PRINT @cmd;
FETCH NEXT FROM c INTO @ln, @rn;
END
CLOSE c;
DEALLOCATE c;
Run Code Online (Sandbox Code Playgroud)
这将打印一堆单独的CREATE DATABASE ... FOR ATTACH
命令。但是,它们的可靠性取决于 (a) 中的数据msdb..backupset
,(b) 实际备份文件的存在,(c) 备份文件在当前数据库文件结构方面的准确性,以及 (d) 您重新旧路径的映射 -> 新路径。
归档时间: |
|
查看次数: |
1094 次 |
最近记录: |