为什么SqlServer有完整备份、差异备份和事务日志备份三种备份方式,以及为什么数据库又有简单模式、完整模式和大容量日志模式这三种恢复模式。本文内容适用于2005以上所有版本的SqlServer数据库。
单就操作过程而言,SqlServer中数据库备份和恢复过程是相当简单的,可以通过ManagementStudio的图形界面进行操作,也可以使用几句T-SQL语句完成。但要明白备份恢复的整个过程,定制符合系统需求数据库备份方案,却需要知晓数据库的实现原理。备份和恢复是数据库的核心功能。
可能许多同学对SQLServer的备份和还原有一些了解,也可能经常使用备份和还原功能,我相信除DBA之外我们大部分开发员队伍对备份和还原只使用最基础的功能,对它也只有一个大概的认识。
一、数据库原理
先简要讨论了SqlServer数据库的存储的物理和逻辑结构,这是备份恢复的理论基础。
1.为什么使用数据库
为什么要使用数据库,而不是使用一个文件,然后自己写一些方法来保存数据,那是因为使用数据库我们就不用自己去实现下面这些算法上非常复杂的功能:
a.高效一致的结构化数据存取方法,进行复杂的任意条件组合嵌套的数据查询(关系数据库管理系统甚至为实现这一功能专门设计了一种语言:SQL)
b.保障数据操作的原子性和完整性
c.确保在服务器断电、网络中断、服务器崩溃、客户端崩溃的情况下,故障恢复后数据仍然是完整的
d.在服务器被完全物理摧毁的情况下,快速在新的服务器上使用远程设备上的备份将数据恢复到灾难发生之前的状态
e.随时将数据恢复到任意时刻或任意一个操作之前
a主要是功能和性能
bcde四条都可以归结为完整性。
数据库系统的核心目标就是:在实现功能需求的基础上,保证数据完整性和数据存取性能。
2.SqlServer存储的物理结构和逻辑结构
(1)如何实现完整性
经过很多理论研究和实践,目前公认的最有效的实现完整性的方法是:将数据的存储分为数据和事务日志,在存取过程中使用锁来控制并发访问。
数据是实时状态。
事务日志记录了数据发生变化的过程,对于数据库数据的任何一个改变,都被作为一条记录写在了事务日志文件中。
事务是指一组操作要么全部成功要么全部不执行。
任何数据更改操作在写入到数据文件中之前,必须先将更前后的数据写入事务日志文件中,这样当事务由于用户取消、数据逻辑错误或软硬件故障中断时能够正确的回滚或前滚到正确的状态。
通过锁控制多用户对同一数据的并发访问。
这是事务系统最基本的原理,大多数关系数据库系统和面向对象NoSQL数据库系统都采用这种方法。
SqlServer也不例外,每个SqlServer数据库由数据文件(*.mdf)和事务日志文件(*.ldf)构成。SqlServer包括了从行到表,从页面到文件的各种粒度的锁。
(2)如何实现高性能
在计算机数据存取过程中,保障性能的算法最终都可以归结为:索引和缓存。从实现层面到应用层面,SqlServer都在建立管理各种索引和各种缓存。
对于需要随机存取的数据,分页是最自然的索引方法,同时能够方便的进行缓存,实现高效率的随机存取。我们所熟悉的操作系统内存管理系统、文件管理系统都采用了分页的方法。
在SqlServer中,对于数据文件mdf,主要是随机存取,因此mdf以分页的形式进行组织管理,每个页面8KB。还进一步将8个相邻的页组成一个扩展,方便管理,类似Windows中的簇。
mdf中保存着多种类型的数据,包括表数据、索引数据和大块数据等等。每个页面只保存一种数据。
表中的每一条记录都保存在一个表数据页中,记录不能跨页,因此任何表中记录的最大长度是略小于8KB(ntext之类的大块列只计算引用的大小)的一个数值,略小是因为每个页面需要一些空间来保存页面自身的信息(页头)和记录在页面中的存储位置。
在SqlServer中,对于事务日志文件ldf,主要是顺序存取。在正常运行时,数据库管理系统定期将日志顺序写入到ldf文件;在恢复时,顺序读取ldf文件。因此,日志文件不需要分页,只要由一条条顺序存储的事务日志记录构成即可。日志记录也有缓存,定期写入到ldf文件。
尽管数据库系统是一个允许并发访问的系统,但是对事务日志的写入是串行化的,不可以并发,任何一个原子操作对应的事务日志记录在事务日志文件中都有其唯一的位置,也就是唯一的事务日志记录编号,这个编号是一直增大的,不会重复,越新的记录编号越大,存储位置也越靠后。
以上内容总结自SqlServer的产品文档SqlServerBooksOnline,如有兴趣可以在里面了解更详细的内容。这些就是备份和恢复的基础原理。
2数据库备份的实现
如前所述,数据文件mdf保存了数据的实时状态,事务日志文件ldf记录了数据库中数据变化的过程。这个时候,我们要对数据库进行备份,自然而然就有两个选择:
因为mdf文件中保存了数据库中数据的实时状态,那么我们只要把mdf文件拷贝一份就实现了当前时刻的数据库备份。
既然ldf文件中保存了数据库中数据变化的整个过程,那么我们就可以把这个ldf文件备份起来,然后用这些备份的事务日志记录从头重建整个数据库,而且比至第一种方法,通过事务日志记录恢复的方法可以将数据库恢复到任一时刻。
实际上,SqlServer同时使用了这两种方法。
恢复模式
右键数据库属性--选项--可以看到“恢复模式”,SQLServer2008数据库恢复模式分为三种:完整恢复模式、大容量日志恢复模式、简单恢复模式,如下图。
完整恢复模式
为默认恢复模式。它会完整记录下操作数据库的每一个步骤。使用完整恢复模式可以将整个数据库恢复到一个特定的时间点,这个时间点可以是最近一次可用的备份、一个特定的日期和时间或标记的事务。
大容量日志恢复模式
简单地说就是要对大容量操作进行最小日志记录,节省日志文件的空间(如导入数据、批量更新、SELECTINTO等操作时)。比如一次在数据库中插入数十万条记录时,在完整恢复模式下每一个插入记录的动作都会记录在日志中,使日志文件变得非常大,在大容量日志恢复模式下,只记录必要的操作,不记录所有日志,这样一来,可以大大提高数据库的性能,但是由于日志不完整,一旦出现问题,数据将可能无法恢复。因此,一般只有在需要进行大量数据操作时才将恢复模式改为大容量日志恢复模式,数据处理完毕之后,马上将恢复模式改回完整恢复模式。
简单恢复模式
在该模式下,数据库会自动把不活动的日志***,因此简化了备份的还原,但因为没有事务日志备份,所以不能恢复到失败的时间点。通常,此模式只用于对数据库数据安全要求不太高的数据库,并且在该模式下,数据库只能做完整和差异备份。
可以看出三种恢复模式的区别在于对“日志”的处理方式不同,就“日志”大小来看:完全恢复模式>大容量日志恢复模式>简单恢复模式。
备份方式
SQLServer2008提供了四种备份方式:完整备份、差异备份、事务日志备份、文件和文件组备份。
完整备份
备份整个数据库的所有内容,包括事务日志。该备份类型需要比较大的存储空间来存储备份文件,备份时间也比较长,在还原数据时,也只要还原一个备份文件。
差异备份
差异备份是完整备份的补充,只备份上次完整备份后更改的数据。相对于完整备份分来说,差异备份的数据量比完整数据备份小,备份的速度也比完整备份要快。因此,差异备份通常作为常用的备份方式。在还原数据时,要先还原前一次做的完整备份,然后还原最后一次所做的差异备份,这样才能让数据库里的数据恢复到与最后一次差异备份时的内容相同。
事务日志备份
事务日志备份只备份事务日志里的内容。事务日志记录了上一次完整备份或事务日志备份后数据库的所有变动过程。事务日志记录的是某一段时间内的数据库变动情况,因此在进行事务日志备份之前,必须要进行完整备份。与差异备份类似,事务日志备份生成的文件较小、占用时间较短,但是在还原数据时,除了先要还原完整备份之外,还要依次还原每个事务日志备份,而不是只还原最后一个事务日志备份(这是与差异备份的区别)。
文件和文件组备份
如果在创建数据库时,为数据库创建了多个数据库文件或文件组,可以使用该备份方式。使用文件和文件组备份方式可以只备份数据库中的某些文件,该备份方式在数据库文件非常庞大时十分有效,由于每次只备份一个或几个文件或文件组,可以分多次来备份数据库,避免大型数据库备份的时间过长。另外,由于文件和文件组备份只备份其中一个或多个数据文件,当数据库里的某个或某些文件损坏时,可能只还原损坏的文件或文件组备份。
举例说明
完整备份
例如,在2012年1月1日早上8点进行了完整备份,那么将来在还原时,就可以恢复到2012年1月有1日早上8点时的数据库状态。
差异备份
差异备份是备份完整备份后的数据变动情况。例如,在2012年1月1日早上8点进行了完整备份后,在1月2日和1月3日又分别进行了差异备份,那么在1月2日的差异备份里记录的是从1月1日到1月2日这一段时间里的数据变动情况,而在1月3日的差异备份里记录的是从1月1日到1月3日这一段时间里的数据变动情况。因此,如果要还原到1月3日的状态,只要先还原1月1日做的完整备份,再还原1月3日做的差异备份就可以了。
事务日志备份
事务日志备份是以事务日志文件作为备份对象,相当于将数据库里的每一个操作都记录下来了。假设在2012年1月1日早上8点进行了完整备份后,到1月2日早上8点为止,数据库里的数据变动了100次,如果此时做了差异备份,那么差异备份记录的是第100次数据变动后的数据库状态,而如果此时做了事务日志备份,备份的将是这100次的数据变动情况。
再举一个例子,例如在2012年1月1日早上8点进行了完整备份后,在1月2日和1月3日又进行了事务日志备份,那么在1月2日的事务日志备份里记录的是从1月1日到1月2日这一段时间里的数据变动情况,而在1月3日的事务日志备份里记录的是从1月2日到1月3日这一段时间里的数据变动情况。因此,如果要还原到1月3日的数据,需要先还原1月1日做的完整备份,再还原1月2日做的事务日志备份,最后还要还原1月3日所做的事务日志备份。
备份方式的选择
了解了以上数据库备份方式后,便可以针对自己的数据库利用以上方式来备份数据库了。合理备份数据库需要考虑几方面,首先是数据安全,其次是备份文件大小,最后是做备份和还原能承受的时间范围。
数据变动量较小
例如,如果数据库里每天变动的数据量很小,可以每周(周日)做一次完整备份,以后的每天(下班前)做一次事务日志备份,那么一旦数据库发生问题,可以将数据恢复到前一天(下班时)的状态。
当然,也可以每周(周日)做一次完整备份,以后的每天(下班前)做一次差异备份,这样一旦数据库发生问题,同样可以将数据恢复到前一天下班时的状态。只是一周的后几天做差异备份时,备份的时间和备份的文件都会跟着增加。但这也有一个好处,在数据损坏时,只要恢复完整备份的数据和前一天差异备份的数据即可,不需要去恢复每一天的事务日志备份,恢复的时间会比较短。
数据变动量较大
如果数据库里的数据变动得比较频繁,损失一个小时的数据都是十分严重的损失时,用上面的办法备份数据就不可行了,此时可以交替使用三种备份方式来备份数据库。
例如,每天下班时做一次完整备份,在两次完整备份之间每隔八小时做一次差异备份,在两次差异备份之间每隔一小时做一次事务日志备份。如此一来,一旦数据损坏可以将数据恢复到最近一个小时以内的状态,同时又能减少数据库备份数据的时间和备份数据文件的大小。
数据库文件较大
在前面还提到过当数据库文件过大不易备份时,可以分别备份数据库文件或文件组,将一个数据库分多次备份。在现实操作中,还有一种情况可以使用到数据库文件的备份。例如在一个数据库中,某些表里的数据变动得很少,而某些表里的数据却经常改变,那么可以考虑将这些数据表分别存储在不同的文件或文件组里,然后通过不同的备份频率来备份这些文件和文件组。但使用文件和文件组来进行备份,还原数据时也要分多次才能将整个数据库还原完毕,所以除非数据库文件大到备份困难,否则不要使用该备份方式。
尾部日志备份
针对以上备份方案,能看出数据还是不完整吗?比如昨天夜间12点做了完整备份,每隔一小时做了一次事务日志备份,最后一次事务日志备份是今天中午12点,现在是今天中午12点10分,发现数据库数据遭到丢失或破坏,可最后一次事务日志备份是今天中午12点,如果我此时将数据库恢复到12点,那么12点后至12点10分前没遭到破坏的操作数据将丢失(比如数据库有三个表,一个表的数据遭到破坏,其它两个表的数据被其它用户变动)。此时就要用到【尾部日志备份】,尾部日志备份原理是从最后一次事务日志备份的时间点开始,将之后的所有操作进行备份,还原时便可以找到12点后操作的正确数据了。
注:进行尾部日志备份时,数据库将强制停止数据库,此时如果不停止数据库,还有用户继续操作,尾部日志备份将失去意义。SQLServer2012如果你最后一次备份事务日志后,对数据进行过改动,即发生过事务日志(也就是当前日志文件记录的LSN(日志序列号)大于最后一次事务日志备份里记录的最大LSN,SQLServer通过LSN来区分日志的记录),并尚未对尾部日志备份,它会提示并要求你必须先做尾部备份。