还原/备份时做了些什么

原文出处:https://blogs.msdn.com/b/psssql/archive/2008/01/23/how-it-works-what-is-restore-backup-doing.aspx

 

一个客户问道:为什么我花了7个小时来备份我的数据库,却要用21个小时来还原?

可能的原因有很多。比如,你有个1TB的数据库,但是只储存了100GB的数据,那么备份的时候,只需要备份这100GB的数据。然而,在还原数据库的时候,你必须重构1TB的数据库,那将意味着大量的时间将被消耗。另一种情况是,你可能没有使用instant file initialization, 将文件预填零操作将会导致大量的写操作。

以下是一次还原操作的错误日志,这通常可以用来决定在备份/还原过程中,哪一步消耗了时间。

2008-01-23 08:38:40.42 spid52 Starting up database 'dbPerf_MAIN'.

2008-01-23 08:38:40.52 spid52 The database 'dbPerf_MAIN' is marked RESTORING and is in a state that does not allow recovery to be run.

2008-01-23 08:38:43.71 spid52 Starting up database 'dbPerf_MAIN'.

2008-01-23 08:38:46.82 Backup Restore is complete on database 'dbPerf_MAIN'. The database is now available.

2008-01-23 08:38:46.82 Backup Database was restored: Database: dbPerf_MAIN, creation date(time): 2008/01/16(14:04:58), first LSN: 647:4889:66, last LSN: 647:4918:1, number of dump devices: 1, device information: (FILE=1, TYPE=DISK: {'c:\temp\dbperf_main.bak'}). Informational message. No user action required.

 

正如以前所提及的(https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930079&SiteID=1), SQLServer确实有一套跟踪标志来为备份或者还原操作提供更详细的信息。

警告: 跟踪标志应在微软SQL Server Support指导下使用。在这里仅作为讨论使用,将不会再后期版本中被支持。

以下的SQL Server 错误日志输出使用了跟踪标志3004来收集额外的信息。跟踪标志3605同样被使用来使输出进入错误日志。

我标亮了正常输出信息来使之更适于被阅读。阅读细节信息可以帮助你了解发生了什么。比如,停止全文搜索发生在你能够看到数据库被启动之前。使用时间戳和相关的信息可以帮助你了解一个标准的还原过程,以及决定哪里将是效率瓶颈。

dbcc traceon(3004, 3605, -1)

restore database dbPerf_MAIN from disk = 'c:\perf.bak' with replace, stats=1 

2008-01-23 08:59:56.26 spid52 RestoreDatabase: Database dbPerf_MAIN

2008-01-23 08:59:56.26 spid52 Opening backup set

2008-01-23 08:59:56.31 spid52 Restore: Configuration section loaded

2008-01-23 08:59:56.31 spid52 Restore: Backup set is open

2008-01-23 08:59:56.31 spid52 Restore: Planning begins

2008-01-23 08:59:56.32 spid52 Halting FullText crawls on database dbPerf_MAIN

2008-01-23 08:59:56.32 spid52 Dismounting FullText catalogs

2008-01-23 08:59:56.32 spid52 X-locking database: dbPerf_MAIN

2008-01-23 08:59:56.32 spid52 Restore: Planning complete

2008-01-23 08:59:56.32 spid52 Restore: BeginRestore (offline) on dbPerf_MAIN

2008-01-23 08:59:56.40 spid52 Restore: PreparingContainers

2008-01-23 08:59:56.43 spid52 Restore: Containers are ready

2008-01-23 08:59:56.43 spid52 Zeroing C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\dbPerf_MAIN_log.LDF from page 1 to 17312 (0x2000 to 0x8740000)

2008-01-23 08:59:56.43 spid52 Restore: Restoring backup set

2008-01-23 08:59:56.43 spid52 Restore: Transferring data to dbPerf_MAIN

2008-01-23 08:59:58.55 spid52 Restore: Waiting for log zero on dbPerf_MAIN

2008-01-23 09:00:00.64 spid52 Zeroing completed on C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\dbPerf_MAIN_log.LDF

2008-01-23 09:00:00.70 spid52 Restore: LogZero complete

2008-01-23 09:00:00.97 spid52 FileHandleCache: 0 files opened. CacheSize: 12

2008-01-23 09:00:00.97 spid52 Restore: Data transfer complete on dbPerf_MAIN

2008-01-23 09:00:00.97 spid52 Restore: Backup set restored

2008-01-23 09:00:01.11 spid52      Starting up database 'dbPerf_MAIN'.

2008-01-23 09:00:01.15 spid52      The database 'dbPerf_MAIN' is marked RESTORING and is in a state that does not allow recovery to be run.

2008-01-23 09:00:01.15 spid52 Restore-Redo begins on database dbPerf_MAIN

2008-01-23 09:00:04.06 spid52 Rollforward complete on database dbPerf_MAIN

2008-01-23 09:00:04.09 spid52 Restore: Done with fixups

2008-01-23 09:00:04.09 spid52 Restore: Transitioning database to ONLINE

2008-01-23 09:00:04.09 spid52 Restore: Restarting database for ONLINE

2008-01-23 09:00:04.31 spid52      Starting up database 'dbPerf_MAIN'.

2008-01-23 09:00:05.32 spid52 FixupLogTail(progress) zeroing C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\dbPerf_MAIN_log.LDF from 0x6cf6c00 to 0x6cf8000.

2008-01-23 09:00:05.32 spid52 Zeroing C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\dbPerf_MAIN_log.LDF from page 13948 to 13960 (0x6cf8000 to 0x6d10000)

2008-01-23 09:00:05.32 spid52 Zeroing completed on C:\Program Files\Microsoft SQL Server\MSSQL10.SQL2008\MSSQL\DATA\dbPerf_MAIN_log.LDF

2008-01-23 09:00:05.38 spid52 PostRestoreContainerFixups: running fixups on dbPerf_MAIN

2008-01-23 09:00:05.38 spid52 PostRestoreContainerFixups: fixups complete

2008-01-23 09:00:05.41 spid52 PostRestoreReplicationFixup for dbPerf_MAIN starts

2008-01-23 09:00:06.04 spid52 PostRestoreReplicationFixup for dbPerf_MAIN complete

2008-01-23 09:00:06.08 spid52 Restore: Database is restarted

2008-01-23 09:00:06.08 Backup      Restore is complete on database 'dbPerf_MAIN'. The database is now available.

2008-01-23 09:00:06.08 spid52 Resuming any halted fulltext crawls

2008-01-23 09:00:06.08 spid52 Restore: Writing history records

2008-01-23 09:00:06.08 Backup      Database was restored: Database: dbPerf_MAIN, creation date(time): 2008/01/16(14:04:58), first LSN: 647:4889:66, last LSN: 647:4918:1, number of dump devices: 1, device information: (FILE=1, TYPE=DISK: {'c:\temp\dbperf_main.bak'}). Informational message. No user action required.

2008-01-23 09:00:06.10 spid52 Writing backup history records

2008-01-23 09:00:06.18 spid52 Restore: Done with MSDB maintenance

2008-01-23 09:00:06.18 spid52 RestoreDatabase: Finished

 

SQL Server的备份和还原是如何选择Transfer Size的

原文出处:https://blogs.msdn.com/b/psssql/archive/2008/02/06/how-it-works-how-does-sql-server-backup-and-restore-select-transfer-sizes.aspx

一个客户问道:为什么Transfer Size在备份时设置为1MB,还原时为64KB,除非我修改BUFFERCOUNT 和MAXTRANSFERSIZE?

警告: 跟踪标志应在微软SQL Server Support指导下使用。在这里仅作为讨论使用,将不会再后期版本中被支持。

dbcc traceon(3605, 3004, 3014, 3213, -1)

这些跟踪标志提供了以下额外信息。

2008-02-06 11:59:31.140 spid51 Backup/Restore buffer configuration parameters

2008-02-06 11:59:31.140 spid51 Memory limit: 3325MB

2008-02-06 11:59:31.140 spid51 Buffer count: 6

2008-02-06 11:59:31.140 spid51 Max transfer size: 1024 KB

2008-02-06 11:59:31.140 spid51 Min MaxTransfer size: 64 KB

2008-02-06 11:59:31.140 spid51 Total buffer space: 6 MB

2008-02-06 11:59:31.140 spid51 Buffers per read stream: 6

2008-02-06 11:59:31.140 spid51 Buffers per write stream: 6

2008-02-06 11:59:31.140 spid51 Tabular data device count: 1

2008-02-06 11:59:31.140 spid51 FileTree data device count: 0

2008-02-06 11:59:31.140 spid51 Filesystem i/o alignment: 512

 

我在SQL Server 2005 SP2上去查看发生了什么。我发现在代码上有几处关键的地方值得我来注意。

ChooseBufferParameters

这个方法确定了所有用来决定MAXTRANSFERSIZEBUFFERCOUNT的方式,通过调整这两者的组合来把缓存分配给各自的steam,这是备份或者还原的一部。

这个方法首先查询MAXTRANSFERSIZE,如果它没有被设置(0),那么从GetSuggestedIoSize取值,否则从MAXTRANSFERSIZE中取值。(总是会被进位到下一个合适的64K)

· 如果我们发现,这是一个单设备的小于10MB的数据库,我们将会把建议容量设置为64K来避免额外的内存过度使用。

· 如果我们发现一个LOG是来自于一个批量Log模式下的数据库,我们在计算分配缓存时就把它认为是一个数据库备份,而不是把他们关注在.LDF文件上。

 

不同的设备类型有其自己的GetSuggestedIoSize实现方式.

 

硬盘

 

读/写操作有不同的默认值

 

·         如果设备处于读状态(还原),或者这是个Desktop或者Express版本,使用64K

·        如果设备处于写状态(备份),而且既不是Desktop也不是Express版本,使用1MB。(更大的写操作容量将降低文件的拓展性,而且不利于NTFS的元数据的维护性)

磁带 

备份或者还原都是用64K除非磁带介质上的Block Size设置为其他的默认值。

VDI

备份或者还原都是用64K。

 

BUFFERCOUNT没有被设置时,每种设备类型有自己的实现方式。.

 

每个设备都暴露一个GetSuggestedIoDepth成员来在BUFFERCOUNT未被设置时来决定默认值。

硬盘

深度默认为3

磁带

深度默认为1

VDI

默认为1,最大为4,基于设备的跨度需求。

 

推荐值会做相应修改。

 

备份数据库

bufferCount += backupDeviceCount

bufferCount += 2 * databaseDeviceCount

还原数据库或者还原文件

bufferCount += 2 * databaseDeviceCount

备份日志或者还原日志

bufferCount += 2 * backupDeviceCount

 

当目标确立后,他们会调整Transfer Size和Block Counts来确定每个Steam都会在适当的内存分配下有缓存来进行工作。

最大可使用容量(缓存池的物理内存 / 16)。参见 GlobalMemoryStatusEx (ullTotalPhys )。这是这台机器上所有的物理内存。所以如果你为一个64GM的机器开启/PAE,而SQL Server的实例没有使用AWE,有可能更多的物理内存将会试图允许更大的备份只是因为/PAE被开启。这个问题你依然在缓存池之外的内存中,它将会限制或者使备份的尝试在大的MAXTRANSFERSIXE和大BUFFERCOUNT下失败。

如果计算超出了内存的1/16 ,容量将会被调整到一个合理的缓存和Transfer Size

 我做了一些测试,默认值在不同的配置文件下被合理的设置以满足备份和还原在性能上的需要。你可以调整这些参数来符合你对特殊系统的性能需要。

 

SQL Server 2005 – 当Checksum失败时的数据恢复可能

原文引用:https://blogs.msdn.com/b/psssql/archive/2008/05/22/how-it-works-sql-server-2005-possible-data-recovery-when-checksum-failure-reported.aspx

Microsoft 和我本人经常会遇到要求恢复被损坏的数据库。这是是已知状态下唯一安全的数据库恢复方法。其他的方法,比如DBCC 修复,会导致数据从数据库移除,从而破坏数据完整性以及其他的业务逻辑。无论什么时候你着手开始从你的备份以外进行数据恢复,你都有可能造成更多的数据损失以及将来应用程序由于数据缺失而引起的问题。

Microsoft和我经常建议开启Checksum来鉴别任何数据损坏。这个为大量客户提供了非常有价值的信息。

我昨天遇到一个有趣的问题有关于PAGEVERIFY CHECKSUM设置。这个Checksum失败看上去和某个字符列的实际内容有关,而并非和数据页的结构或者页中的行有关。所以损坏可能是将“Street”错误的改为“StrAet”。然而,当一个页面被鉴别为checksum失败时,整个页面都会显得不稳定。我们需要尽可能的恢复数据页上的这些行列。

当我们发现行级损坏时,我们通常使用一个查询语句来通过索引以强制获取损坏周围的行。因为整个数据页被标记成Checksum失败,所以我们无法访问任何该页的行。

Checksum验证是在数据库级别(PAGEVERIFY)来控制。如果你设置PAGEVERIFY为NONE,Checksum将被忽略访问数据页。注意:这样做可能导致其他不期望的行为,所以只在可控制的环境下允许这个操作。

以下是一个例子:一个小型Window应用程序通过关闭CHECKSUM来允许数据被获取。

· 我创建一个示例数据库。

· 用十六进制的编辑器来模拟一个损坏。

· 将PAGEVERIFY设置为NONE来避免问题。

usemaster

go  

dropdatabase dbTest

go  

createdatabase dbTest

go  

ALTERDATABASE dbTest setPAGE_VERIFYCHECKSUM

go  

use dbTest

go  

createtable tblTest(iID intidentity(1,1), strData nchar(50))

go  

insertinto tblTest values('First Row')

insertinto tblTest values('Second Row to be damaged')

insertinto tblTest values('Third Row')

go  

--     找到第一页

select*fromsys.system_internals_allocation_units

        where container_id =(select hobt_id from sys.partitions where object_id=object_id('tblTest'))

go

usemaster

go

ALTERDATABASE dbTest setOFFLINE

go  

-- 通过16进制编辑器来引入checksum失败

ALTERDATABASE dbTest setONLINE

go  

dbcc checkdb(dbTest) -- 由于Checksum而失败

go  

ALTERDATABASE dbTest setPAGE_VERIFYNONE

go  

dbcc checkdb(dbTest) -- 这里成功了 (数据依然损坏,但是仍然可以通过select语句来获取)

go

 

注意到我用十六进制编辑器来修改了第二行的‘to’。见高亮。

 推荐开启PAGEVERIFY CHECKSUM。你可以注意到所有在该表中损坏数据页的行被认为是无效或者丢失的。

DBCC results for 'tblTest'.

Msg 8928, Level 16, State 1, Line 1

Object ID 2073058421, index ID 0, partition ID 72057594038321152, alloc unit ID 72057594043301888 (type In-row data): Page (1:73) could not be processed. See other errors for details.

Msg 8939, Level 16, State 98, Line 1

Table error: Object ID 2073058421, index ID 0, partition ID 72057594038321152, alloc unit ID 72057594043301888 (type In-row data), page (1:73). Test (IS_OFF (BUF_IOERR, pBUF->bstat)) failed. Values are 12716041 and -4.

There are 0 rows in 0 pages for object "tblTest".

 

简单的使用ALTER DATABASE to PAGEVERIFY NONE, checksum 的问题将在数据页的检查行中被忽略。在这种情况下,数据被损坏但是列依然可以互动而没有进一步的错误。如果数据的长度也被损坏,DBCC将会报一个行级错误。

DBCC results for 'tblTest'.

There are 3 rows in 1 pages for object "tblTest".

 

DBCC Shrink*时更多的事件

原文引用:https://blogs.msdn.com/b/psssql/archive/2008/06/18/how-it-works-more-on-dbcc-shrink-activities.aspx

我的伙计们开始称我为dbcc shrink* 专家(哈哈),所以我来揭秘另一个shrinkfile的技巧来帮助解决SQL Server 2000的问题。

情景: dbcc shrinkfile,设置EMPTYFILE,来操作一个128页将耗费几个小时来完成。虽然说这个本就设计如此,但是并非是我所期待的设计。

以下是在收缩这个文件时所发生的事情:

· 收缩操作建立一个GAM扫描被收缩文件。从数据页一开始开始读取 … 1,2,3…

· 当每个页被处理时,页面类型将被用来决定数据迁移的必要操作。对于数据页来说,这会导致成对的删除和插入操作来吧行移入另一个文件,由此EMPTYFILE可以被完成。

· 当一个BLOB页面被处理时,我想,每个碎片将会被移入另一个文件的新的页面。这个确实发生了,但并非如我所阐述这般。因为BLOB的随便并没有被连接起来,一个更大范围的扫描将发生来来定位那些需要被移动碎片链的根节点。

o 当一个BLOB页面被定位,一个新的扫描将被建立。新的扫描是一个IAM扫描,将扫描原文件中该对象的TEXT/IMAGE BLOB )链。

o IAM链中的每个页面将会被读入,每个碎片也会被审阅。

o 任何一个被发现在EMPTIED文件上的碎片将被标识,相应的BLOB链会被移动。

所以移动一个BLOB页面会要求整个BLOB链将会被扫描。在这个客户的示例中,他们有1TB的数据库而BLOB索引有 ~500GB 。所以移动BLOB页面会有很多的I/O和扫描将会发生。

我没有研究过在SQL Server 2005下的行为方式。

你可以通过我以前发表的文章来了解更多的关于文件收缩的话题。

https://blogs.msdn.com/psssql/archive/2008/03/28/how-it-works-sql-server-2005-dbcc-shrink-may-take-longer-than-sql-server-2000.aspx

https://blogs.msdn.com/psssql/archive/2008/03/24/how-it-works-dbcc-shrinkdatabase-shrinkfile-tabular.aspx

关键词 : shrinkfile, shrinkdb, shrinkdatabase