四巨头第十五周作业翻译

SQL Server中事务日志管理的阶梯,第一级:事务日志概述

系列

本文是阶梯系列的一部分:SQL Server中的事务日志管理的阶梯。

当事情进展顺利时,不需要特别注意事务日志的作用或它是如何工作的。你只需要确信每个数据库都有正确的备份机制。当事情出错时,对事务日志的理解对于采取纠正措施非常重要,特别是当需要一个时间点恢复数据库时,这是非常紧急的!Tony Davis提供了每个DBA都应该知道的适当的细节级别。

第1级:事务日志概述

事务日志是一个文件,其中SQL Server存储与日志文件相关联的数据库上执行的所有事务和数据修改的记录。如果发生导致SQL Server意外关闭的灾难(例如实例或硬件故障),则使用事务日志来恢复数据库,并立即执行数据完整性。在重新启动时,数据库进入一个恢复过程,在该过程中读取事务日志,以确保将所有有效的已提交数据写入数据文件(前滚),并撤消任何部分未提交的事务的影响(回滚)。简而言之,事务日志是SQL Server确保数据库完整性和事务的ACID属性(尤其是持久性)的基本手段。

DBA在管理事务日志方面的一些最重要职责如下:

选择正确的恢复模型- SQL Server提供三个数据库恢复模型:FULL(默认),SIMPLE和BULK日志。DBA必须根据数据库的业务需求选择适当的模型,然后建立适合该模式的维护过程。

执行事务日志备份——除非以简单模式工作,否则DBA执行事务日志的常规备份是至关重要的。一旦在备份文件中捕获,日志记录可以随后应用到完整的数据库备份,以便执行数据库恢复,因此可以重新创建以前存在的数据库,例如在发生故障之前。

监视和管理日志增长—在繁忙的数据库中,事务日志的大小可以快速增长。如果没有定期备份,或者大小不合适,或者分配了不正确的增长特征,事务日志文件就会被填满,导致臭名昭著的“9002”(事务日志已满)错误,这将使SQL Server进入“只读”模式(如果在恢复期间发生,则进入“资源暂挂”模式)。

优化日志吞吐量和可用性——除了进行备份等基本维护之外,DBA还必须采取步骤确保事务日志的适当性能。这包括硬件方面的考虑,以及避免可能影响事务性能的日志碎片等情况。

在这个楼梯系列中,我们将详细地考虑这些核心维护任务。在这里,首先,我们将概述SQL Server如何使用事务日志,以及它影响DBA生命周期的两种最重要的方式,即数据库恢复和恢复,以及磁盘空间管理。

SQL Server如何使用事务日志

在SQL Server中,事务日志是一个物理文件,通过扩展LDF按常规标识(尽管不是强制标识)。它是在创建数据库和主数据文件时自动创建的,主数据文件通常由MDF扩展标识,不过也可以使用任何扩展来存储数据库对象和数据本身。事务日志虽然通常作为单个物理文件实现,但也可以作为一组文件实现。然而,即使在后一种情况下,它仍然是被SQL Server作为一个顺序文件,因此,SQL Server不能并行,不写多个日志文件,所以没有性能优势实现事务日志的多个文件。这将在第7级-调整大小和增加事务日志中进行更详细的讨论。

每当T-SQL代码对数据库对象(DDL)或它包含的数据进行更改时,不仅数据文件中更新了数据或对象,而且更改的细节也被记录为事务日志中的日志记录。每个日志记录都包含关于执行更改的事务ID的详细信息,当事务开始和结束时,更改了哪些页面,更改了哪些数据,等等。

注意:事务日志不是审计跟踪。它不提供对数据库所做更改的审计跟踪;它不保存对数据库执行的命令的记录,只保存数据如何变化的结果。

当进行数据修改时,相关的数据页有望从数据缓存中读取,如果不在缓存中,则首先从磁盘中检索。在数据缓存中修改数据,并在日志缓存中创建描述事务影响的日志记录。当提交事务时,日志记录被写到磁盘上的事务日志中。但是,实际更改的数据可能直到稍后发生数据库检查点时才写入磁盘。缓存中的任何页面在从磁盘读取之后被修改,因此缓存中的数据值与磁盘上的数据不同,称为脏页。这些脏页可能包含这两种内容:

l  已提交并“硬化”到事务日志文件但尚未提交到数据文件的数据

l  由开放事务修改的数据,即尚未提交(或回滚)的数据

定期的数据库检查点进程扫描数据缓存,并将所有脏页面刷新到磁盘,在此情况下,修改将反映在物理数据文件和日志文件中。即使在事务仍然打开的情况下也会发生这种情况;在检查点期间,与打开事务相关的脏页被刷新到磁盘,SQL Server始终确保在脏页刷新到数据文件之前,与这些打开事务相关的日志记录从日志缓存刷新到事务日志文件。

注意:另一个扫描数据缓存的进程LazyWriter,如果由于内存压力而被迫这样做,也可以将脏数据页写到检查点之外的磁盘上。

这里需要注意的重要一点是,日志缓冲区管理器总是确保在将数据页写到物理数据文件之前,将更改描述(日志记录)写到磁盘上的事务日志。这种机制称为预写日志记录。它本质上是SQL Server确保事务持久性的机制(参见数据库事务的ACID属性)。

总是先写更改日志文件,SQL Server的基础机制,可以保证所有已提交的事务的影响最终将反映在数据文件,并修改磁盘上的任何数据,来自不完整的交易,即那些提交和回滚的最终发行不反映在数据文件中。

例如,如果数据库崩溃,在提交某个事务(T1)之后,但在将受影响的数据写到数据文件之前,然后在重新启动时,启动数据库恢复进程,该进程试图协调事务日志文件和数据文件的内容。它将读取事务日志文件,并确保在日志文件中记录的包含事务T1的所有操作都被“前滚”(重做),以便在数据文件中反映出来。

同样,在数据库崩溃之后,通过从日志文件中读取相关操作并对数据执行反向物理操作,恢复过程将“回滚”(撤消)与未提交事务关联的数据库中的任何数据更改。

以这种方式,在发生崩溃时,SQL Server可以将数据库返回到一致的状态。更一般地说,如果:

l  为显式事务发出回滚命令

l  发生错误并打开XACT_ABORT

l  如果数据库检测到数据库和触发事务的客户端之间的通信中断。

    在这种情况下,将读取与中断事务相关的日志记录(或显式发出回滚命令的日志记录),并回滚更改。通过这些方式,SQL Server确保与事务相关的所有操作作为一个单元获得成功,或者所有操作都失败。因此,事务日志是SQL Server在日常操作中确保数据一致性和完整性的基本方法之一。

然而,事务日志扮演着另一个重要的角色,它提供了一种机制,在发生灾难时,通过这种机制可以将数据库恢复到以前的某个时间点。通过适当的计划和管理,你可以使用这些日志文件的备份来恢复所有数据,直到数据损坏或无法使用为止。

事务日志和数据库恢复

正如前面所讨论的,事务日志文件存储一系列日志记录,按照事务开始时的顺序排列,这提供了针对该数据库的修改和事务的历史记录。每个日志记录都包含关于执行更改的事务ID的详细信息,当事务开始和结束时,更改了哪些页面,更改了哪些数据,等等。事务日志文件中的日志记录被组织成多个部分,称为虚拟日志文件(VLFs)——这些在第2级事务日志体系结构中有更详细的介绍。

SQL Server的预写日志机制保证在将修改后的数据本身写入数据文件之前,修改的描述(即日志记录)将被写入VLF。因此,日志记录可能包含已关闭(提交)事务或打开(未提交)事务的详细信息,在每种情况下,事务修改的数据可能已经写入数据文件,也可能没有写入,这取决于是否发生了检查点。

注意:通过定期将脏页从缓存刷新到磁盘,数据库检查点过程控制数据库恢复操作期间SQL Server需要完成的工作量。如果SQL Server必须为大量与脏页相关的提交事务前滚更改,那么恢复过程可能会非常漫长。

与开放事务相关的任何日志记录都可能需要在恢复期间进行回滚操作,并且始终是被称为活动VLF的一部分,并且将始终保留在日志文件中。与已关闭事务相关的日志记录也将是活动VLF的一部分,直到到达与开放事务关联的整个VLF中没有日志记录的点时,VLF将变得不活动。

这些非活动的VLFs中的日志记录实质上提供了以前完成的数据库事务的“历史”,而这些非活动的VLFs发生了什么变化取决于数据库的恢复模型。我们将详细讨论这些复苏模型级别3 - 6的楼梯,但这里的关键是,如果你使用的是完整的(或批量记录)数据库恢复模型,那么事务日志保留在不活跃的甚低频日志记录,直到一个日志备份(不久)。

通过备份事务日志,我们可以将活动日志中的所有日志记录(包括这些非活动的VLFs中的记录)捕获到一个备份文件中。然后可以使用这些日志备份将数据库恢复到以前的时间点;希望时间上的某个点非常接近发生“灾难”的那个点。这样的灾难时,日志备份文件可以应用于恢复完全数据库备份文件的副本,和完整备份之后发生的任何交易将“向前滚”,在数据库恢复,恢复数据库和恢复数据到一个给定的时间点上,所以任何数据损失最小化。当然,这假定你不仅已经进行了这些日志备份,而且还将它们转移到一个安全的位置。如果你的日志备份文件与活动日志文件位于同一驱动器上,并且该驱动器崩溃,那么您可能会丢失所有备份。

当一个数据库处于简单的恢复模型中(第3和第4级对此有更多了解)时,将保留活动VLFs中的日志记录,因为回滚操作可能需要这些记录。但是,当发生检查点时,非活动的VLFs将被截断,这意味着可以立即用新的日志记录覆盖这些VLFs中的日志记录。这就是为什么在简单恢复中操作的数据库被称为处于自动截断模式。在这种模式下,日志中不维护“历史”,因此无法在日志备份中捕获历史并作为恢复过程的一部分使用。

控制日志文件的大小

希望前面的讨论已经清楚地表明,对于运行在完全恢复模型中的大多数生产数据库,有必要对事务日志文件进行定期备份,以便使数据库恢复到特定的时间点。

但是,在以FULL(或bulk_log)模式操作时进行这些日志备份还有第二个重要原因,即控制日志的大小。请记住,对于修改SQL Server数据库中的数据或对象的每个事务,日志记录都被写入到日志文件中。在一个繁忙的系统中,有许多并发事务,或者有许多数据编写,事务日志的大小可以快速增长。

在使用FULL(或bulk_log)模式时,在备份文件中捕获非活动VLFs中的日志记录副本是使这些VLFs符合截断条件的惟一操作,这意味着日志记录所占用的空间可以被重用。

关于截断和事务日志大小的简要说明:有一个常见的误解,即截断日志文件意味着删除日志记录,文件的大小减少。并不是这样;日志文件的截断仅仅是标记空间以便重用的行为。在每个不同恢复模型的上下文中,将在后续的级别中更详细地讨论截断。

因此,当在FULL(或bulk_log)模式下工作时,执行常规事务日志备份至关重要,其中一个原因是控制日志的大小。

备份事务日志的简单示例

为了简要说明我们在第一个级别中讨论过的一些概念,我们将介绍一个非常简单的示例,该示例支持在完全恢复模式下操作的数据库的事务日志。每个进程和命令的详细信息将在后续的级别中详细介绍。

在清单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%。

注意:在实例上创建的用户数据库的初始大小和增长特征由模型数据库的属性决定,每个数据库将使用的默认恢复模型(在本例中为FULL)也是如此。我们将在第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所示。这个脚本的作者是Jeff Moden,他经常出现在SQLServerCentral.com论坛上。不要担心代码的细节;这里唯一重要的是我们插入了很多行。这段代码可能需要几秒钟在您的机器上执行,这并不是因为代码效率低下;所有的工作都在幕后进行,写数据和日志文件。

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表插入100万行

请注意,日志文件的大小已经膨胀到大约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如何将事务日志文件的内容捕获到一个备份文件中,然后可以重用该文件以作为恢复过程的一部分来恢复数据库。最后,我们强调了备份在控制事务日志大小方面的重要性。

在下一个级别中,我们将更深入地研究事务日志的体系结构。

猜你喜欢

转载自www.cnblogs.com/hawking-520/p/9194182.html