SQL Server中的事务日志管理的阶梯,级别1:事务日志概述
SQL Server中的事务日志管理的阶梯,级别1:事务日志概述
翻译:刘琼滨 谢雪妮 许雅莉 赖慧芳
级别1:事务日志概述
事务日志是一个文件,其中SQL服务器存储了所有与日志文件关联的数据库执行的所有事务和数据修改的记录。如果发生了导致SQL服务器意外关闭的灾难,比如实例或硬件故障,则使用事务日志恢复数据库,并在tact中使用数据完整性。在重新启动时,数据库进入一个恢复过程,其中读取事务日志以确保所有有效的、提交的数据被写入到数据文件(向前滚),以及任何部分、未提交的事务被撤销(回滚)。简而言之,事务日志是SQL Server确保数据库完整性和事务的ACID属性(尤其是持久性)的基本手段。
DBA在管理事务日志方面的一些最重要职责如下:
选择正确的恢复模型——SQL Server提供三个数据库恢复模型:FULL(默认),SIMPLE和BULK日志。DBA必须根据数据库的业务需求选择适当的模型,然后建立适合该模式的维护程序。
执行事务日志备份——除非在简单模式下工作,DBA必须定期执行事务日志的备份。一旦在备份文件中捕获,可以随后将日志记录应用于完整的数据库备份,以执行数据库恢复,因此在失败之前,以之前的时间点重新创建数据库。
监视和管理日志增长——在繁忙的数据库中,事务日志可以快速增长。如果没有定期备份,或者如果不适当大小,或分配不正确的增长特性,事务日志文件就会被填满,导致臭名昭著的“9002”(事务日志全)错误,将SQL Server放入“只读”模式(或者在恢复期间发生“资源待定”模式)。
优化日志吞吐量和可用性——除了进行基本的维护,例如进行备份,DBA必须采取步骤来确保事务日志的足够性能。这包括硬件考虑,以及避免诸如日志碎片这样会影响事务性能的情况.
在这个阶梯系列中,我们将详细讨论这些核心维护任务。在这里,在第一个层次上,我们将首先概述SQL服务器如何使用事务日志,以及它影响DBA生命的两个最重要的方法,即数据库恢复和恢复,以及磁盘空间管理。
SQL服务器如何使用事务日志
在SQL Server中,事务日志是一个物理文件,它是由扩展LDF来识别的,虽然不是强制的。它是在创建数据库时自动创建的,以及主要的数据文件,通常由MDF扩展标识,但也可以使用任何扩展,存储数据库对象和数据本身。事务日志虽然通常作为一个物理文件实现,但也可以作为一组文件实现。然而,即使在后一种情况下,它仍然是被SQL Server作为一个顺序文件,因此,SQL Server不能并行,不写多个日志文件,所以没有性能优势实现事务日志的多个文件。在级别7 -分级和增长事务日志中详细讨论了这个问题。
每当t - sql代码对数据库对象(DDL)或它所包含的数据进行更改时,不仅是数据文件中更新的数据或对象,而且更改的细节也被记录为事务日志中的日志记录。每个日志记录包含关于执行更改的事务ID的详细信息,当事务开始并结束时,更改了哪些页面,更改了哪些数据,等等。
注意:事务日志不是审计跟踪。它不提供对数据库的更改的审计跟踪;它没有记录对数据库执行的命令的记录,只是数据是如何改变的。
当进行数据修改时,希望从数据缓存中读取相关数据页,或者从磁盘中读取数据页,如果它们还没有在缓存中。在数据缓存中修改数据,并在日志缓存中创建日志记录来描述事务的影响。当事务提交时,日志记录被写到磁盘上的事务日志。然而,实际更改的数据可能要到稍后才会写到磁盘,这时会出现一个数据库检查点。缓存中的任何页面都被从磁盘读取后进行了修改,因此缓存中的数据值与磁盘上的数据值不同,称为“脏页”。这些脏页可能包括:
对事务日志文件已提交并“淬火”的数据,但尚未提交到数据文件。
被公开交易修改的数据,即尚未提交(或回滚)的数据。
定期的数据库检查点进程扫描数据缓存,并将所有脏页面刷新到磁盘,此时,修改将反映在物理数据文件和日志文件中。即使在交易仍然开放的情况下,这种情况也会发生;在检查点期间,与开放事务相关的脏页面被刷新到磁盘,而SQL服务器总是确保与这些开放事务相关的日志记录从日志缓存刷新到事务日志文件,然后将脏页面刷新到数据文件。
注意:另一个扫描数据缓存的过程,即LazyWriter,也可以在检查点之外的磁盘上写脏数据页,如果由于内存压力而被迫这样做的话。
这里需要注意的重要一点是,日志缓冲区管理器始终保证在将数据页写入物理数据文件之前,更改描述(日志记录)被写到磁盘上的事务日志中。这种机制称为写前日志记录。它本质上是SQL服务器确保事务持久性的机制(参见数据库事务的ACID属性)。总是先写更改日志文件,SQL Server的基础机制,可以保证所有已提交的事务的影响最终将反映在数据文件,并修改磁盘上的任何数据,来自不完整的交易,即那些提交和回滚的最终发行不反映在数据文件中。例如,如果数据库崩溃,在某个事务(T1)提交之后,但在受影响的数据写入数据文件之前,然后重启后,将启动数据库恢复过程,以协调事务日志文件和数据文件的内容。它将读取事务日志文件,并确保包含在日志文件中记录的事务T1的所有操作都“向前滚”(重做),以便它们反映在数据文件中。同样,在数据库崩溃之后,恢复过程将“回滚”(撤消)数据库中与未提交事务相关的任何数据更改,通过读取日志文件中的相关操作,并对数据执行反向物理操作。
这样,在发生崩溃时,SQL Server可以将数据库返回到一致的状态。更一般地,回滚(撤销)过程发生:
为显式事务发出回滚命令。
发生错误,打开XACT_ABORT。
如果数据库检测到在数据库和发起事务的客户机之间已经断开了通信。
在这种情况下,将读取与中断事务相关的日志记录,或显式地发出回滚命令的日志记录,以及回滚的更改。在这些方面,SQL Server确保了所有与事务关联的操作成功,作为一个单元,或者它们都失败了。因此,事务日志表示SQL服务器在正常的日常操作中确保数据一致性和完整性的基本方法之一。
然而,事务日志扮演着另一个重要的角色,它提供了一个机制,在灾难发生的情况下,数据库可以被恢复到以前的时间点。通过适当的计划和管理,您可以使用这些日志文件的备份来恢复所有的数据,直到它损坏或无法使用为止。
事务日志和数据库恢复
正如前面所讨论的,事务日志文件存储了一系列日志记录,按照事务启动时的顺序进行排序,这提供了对该数据库的修改和事务的历史记录。每个日志记录包含关于执行更改的事务ID的详细信息,当事务开始并结束时,更改了哪些页面,更改了哪些数据,等等。事务日志文件中的日志记录被组织成多个部分,称为虚拟日志文件(VLFs)——这些在第2级事务日志体系结构中更加详细。
SQL Server的写前日志记录机制保证在将修改的数据写入数据文件之前,对修改的描述(即日志记录)写入VLF。因此,日志记录可能包含关闭(提交的)事务或open(未提交)事务的详细信息,在每个情况下,事务修改的数据可能已经写入数据文件,也可能不写入数据文件,这取决于检查点是否发生了。
注意:通过定期将脏页面从缓存刷新到磁盘,数据库检查点流程控制在数据库恢复操作期间需要做的工作SQL Server的数量。如果SQL Server必须对与脏页相关的大量提交事务进行更改,那么恢复过程可能非常漫长。
与开放事务相关的任何日志记录都可能需要在恢复期间进行回滚操作,并且始终是被称为active VLF的一部分,并且将始终保留在日志文件中。与闭事务相关的日志记录也将是一个活动的VLF的一部分,直到在整个VLF中没有日志记录与一个开放事务关联,此时VLF变得不活跃。
这些非活动的VLFs中的日志记录本质上提供了之前完成的数据库事务的“历史”,而这些非活动的VLFs的发生变化取决于数据库的恢复模型。我们将详细讨论这些复苏模型级别3 - 6的楼梯,但这里的关键是,如果您使用的是完整的(或批量记录)数据库恢复模型,那么事务日志保留在不活跃的甚低频日志记录,直到一个日志备份(不久)。
通过备份事务日志,我们可以捕获到日志中所有日志记录的备份文件,包括这些非活动的VLFs中的日志记录。然后可以使用这些日志备份将数据库恢复到以前的时间点;希望有一个时间点非常接近于一些“灾难”发生的点。这样的灾难时,日志备份文件可以应用于恢复完全数据库备份文件的副本,和完整备份之后发生的任何交易将“向前滚”,在数据库恢复,恢复数据库和恢复数据到一个给定的时间点上,所以任何数据损失最小化。当然,这假设您不仅使用了这些日志备份,还将它们转移到一个安全的位置。如果您的日志备份文件与live日志文件在同一驱动器上,并且该驱动器崩溃,那么您可能会丢失所有备份。
当数据库在简单的恢复模型中(在第3和4级上更多),在活动的VLFs中记录日志记录,因为它们可能需要回滚操作。然而,当一个检查点发生时,非活动的VLFs将被截断,这意味着这些VLFs中的日志记录可以立即覆盖新的日志记录。这就是为什么在简单的恢复中运行的数据库被称为自动截断模式。在这种模式下,日志中没有维护“历史”,因此无法在日志备份中捕获它,并作为恢复过程的一部分使用。
控制日志文件的大小
希望前面的讨论已经清楚地表明,对于大多数在完全恢复模型中运行的生产数据库来说,需要定期对事务日志文件进行备份,以使数据库恢复到特定的时间点。
但是,有第二个重要的原因是在运行在FULL(或隔离日志)模式下运行这些日志备份,这是为了控制日志的大小。请记住,日志记录被写到日志文件中,用于修改SQL Server数据库中的数据或对象。在一个繁忙的系统中,有许多并发事务,或者是编写大量数据的事务,事务日志可以非常快地增长。
当在FULL(或散货)模式中工作时,在备份文件中捕获非活动的VLFs中日志记录的副本,这是唯一能够使那些VLFs有资格进行截断的操作,这意味着日志记录所占用的空间可以用于重用。
关于截断和事务日志大小的简短说明: 有一个常见的误解,就是截删日志文件意味着日志记录被删除,文件大小减少。它不;日志文件的截断仅仅是标记空间以便重用的行为。在每个不同的恢复模型的上下文中,截断将在以后的级别中进行更详细的讨论。
因此,当在FULL(或散货)模式中工作时,执行常规事务日志备份是至关重要的,其中一个原因是控制日志的大小。
一个备份事务日志的简单示例
为了简要说明我们在第一个层次中讨论的一些概念,我们将介绍一个简单的例子,它支持在完全恢复模式下运行数据库的事务日志。每个过程和命令的详细信息将在随后的级别中详细讨论。
在清单1.1中,我们在SQL Server 2008实例上创建了一个新的TestDB数据库,然后使用DBCC SQLPERF(LOGSPACE)命令立即获得日志文件的大小。
USE master ;
IF EXISTS ( SELECT name
FROM sys.databases
WHERE name = 'TestDB' )
DROP DATABASE TestDB ;
CREATE DATABASE TestDB ON
(
NAME = TestDB_dat,
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Data\TestDB.mdf'
) LOG ON
(
NAME = TestDB_log,
FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Data\TestDB.ldf'
) ;
DBCC SQLPERF(LOGSPACE) ;
Database Name Log Size (MB) Log Space Used (%) Status
---------------------------------------------------------
master 1.242188 34.27673 0
...<snip>...
TestDB 0.9921875 31.74213 0
清单1.1:新的TestDB数据库的初始日志文件大小。
正如您所看到的,日志文件目前大约有1 MB大小,大约30%满。
注意:在实例上创建的用户数据库的初始大小和增长特征是由模型数据库的属性决定的,这是每个数据库将要使用的默认恢复模型(在本例中是完整的)。我们将在7级调整和增长事务日志中详细讨论这些属性的影响。
只需将物理文件定位到磁盘上即可确认文件的大小,如图1.1所示。
图1.1:TestDB的数据和日志文件
现在,让我们为TestDB执行数据文件的备份,如清单1.2所示(首先需要创建“备份”目录)。注意,此备份操作确保数据库真正处于完全恢复模式下运行;在第3级-事务日志、备份和恢复中有更多内容。
-- full backup of the database
BACKUP DATABASE TestDB
TO DISK ='C:\Backups\TestDB.bak'
WITH INIT;
GO
清单1.2:TestDB的初始完全备份。
由于这个备份操作,或者使用了日志空间的百分比,所以数据或日志文件的大小没有变化,这可能不足为奇,因为数据库中没有用户表或数据。让我们把这个设置好,并在这个数据库上创建一个名为LogTest的表,填满100万行数据,再检查日志文件大小,如清单1.3所示。这个脚本的作者,经常在SQLServerCentral.com论坛上看到,是Jeff Moden,他得到了他的许可。不要担心代码的细节;这里唯一重要的是我们插入了很多行。这段代码可能需要几秒钟才能在您的机器上执行,这并不是因为代码效率低下;所有的工作都在后台进行,写入数据和日志文件。
USE TestDB ;
GO
IF OBJECT_ID('dbo.LogTest', 'U') IS NOT NULL
DROP TABLE dbo.LogTest ;
--===== AUTHOR: Jeff Moden
--===== Create and populate 1,000,000 row test table.
-- "SomeID" has range of 1 to 1000000 unique numbers
-- "SomeInt" has range of 1 to 50000 non-unique numbers
-- "SomeLetters2";"AA"-"ZZ" non-unique 2-char strings
-- "SomeMoney"; 0.0000 to 99.9999 non-unique numbers
-- "SomeDate" ; >=01/01/2000 and <01/01/2010 non-unique
-- "SomeHex12"; 12 random hex characters (ie, 0-9,A-F)
SELECT TOP 1000000
SomeID = IDENTITY( INT,1,1 ),
SomeInt = ABS(CHECKSUM(NEWID())) % 50000 + 1 ,
SomeLetters2 = CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65)
+ CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65) ,
SomeMoney = CAST(ABS(CHECKSUM(NEWID())) % 10000 / 100.0 AS MONEY) ,
SomeDate = CAST(RAND(CHECKSUM(NEWID())) * 3653.0 + 36524.0 AS DATETIME) ,
SomeHex12 = RIGHT(NEWID(), 12)
INTO dbo.LogTest
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2 ;
DBCC SQLPERF(LOGSPACE) ;
清单1.3:在TestDB中,将一百万行插入到LogTest表中。
注意日志文件的大小已经膨胀到将近110 MB,日志的大小已经达到了91%(在您的系统上数据可能略有不同)。如果我们要插入更多的数据,它将不得不再次增长以容纳更多的日志记录。同样,可以从物理文件确认大小的增加(数据文件已经增加到64 MB)。
我们可以在这个时候再次备份数据文件,重新运行清单1.2,它对日志文件的大小和文件中使用的空间百分比没有影响。现在,让我们备份事务日志文件并重新检查值,如清单1.4所示。
-- now backup the transaction log
BACKUP Log TestDB
TO DISK ='C:\Backups\TestDB_log.bak'
WITH INIT;
GO
DBCC SQLPERF(LOGSPACE) ;
Database Name Log Size (MB) Log Space Used (%) Status
-------------------------------------------------------
master 1.242188 63.52201 0
...<snip>…
TestDB 99.74219 6.295527 0
清单1.4:备份TestDB的事务日志
日志文件的物理大小仍然相同,但是通过备份文件,SQL Server能够截断日志,使日志文件中的“非活动”VLFs空间可以重用;可以添加更多的日志记录,而不需要物理地扩展文件。当然,我们已经将日志记录捕获到备份文件中,因此可以将该文件作为数据库恢复过程的一部分使用,我们需要将TestDB数据库恢复到以前的状态。
摘要
在第一个层次中,我们引入了事务日志,并解释了SQL Server如何通过写前日志记录机制来维护数据一致性和完整性。我们还简要地介绍了DBA如何将事务日志文件的内容捕获到备份文件中,然后可以重用该文件以恢复数据库作为恢复过程的一部分。最后,我们强调了备份在控制事务日志大小方面的重要性。
在下一层中,我们将进一步了解事务日志的架构。
资源:
This article is part of the Stairway to Transaction Log Management in SQL Server Stairway
Sign up to our RSS feed and get notified as soon as we publish a new level in the Stairway!