【转】为什么事务日志自动增长会降低你的性能

在这篇文章里,我想详细谈下为什么你要避免事务日志(Transaction Log)上的自动增长操作(Auto Growth operations)。很多运行的数据库服务器,对于事务日志,用的都是默认的日志文件大小和自动增长设置。人们有时会很依赖自动增长机制,因为它们刚好能正常工作。当然,如果它正常工作的话,你不必太关注它,但很快你会发现会有问题出现。

只依赖于事务日志的自动增长机制总不是个好主意。首先它会导致严重的日志碎片(Log Fragmentation),在SQL Server启动期间,在你数据库上执行崩溃恢复(Crash Recovery)时会有很大的负面影响。另外,在你数据库里写入事务需要等待,只要事务日志触发了自动增长机制。

当事务日志的自动增长机制发生时,SQL Server总要零初始化新块,这个会在文件末尾加上。这和你的SQL Server实例是否用即时文件初始化(Instant File Initialization)特权——事务日志总会零初始化。这上面的原因非常明显:当SQL Server在过去已经完成事务日志的环绕式处理(wrap-around ),崩溃恢复(Crash Recovery)需要知道在哪里停。

零初始化的问题是会占用更多的时间(取决与你的自动增长率,还有你的存储速度)。在此期间没有别的事务可以写事务日志记录到事务日志。在事务日志管理器上会有闩锁造成的阻塞。因此你的写入事务会进入挂起状态(直到它们获得需要的闩锁),它们就等啊,等啊,等啊,直到你的事务日志自动增长完成。让我们用一个简单的例子演示下。

首先我为这个演示创建一个新的数据库。对于这个数据库,这里我不用默认的设置,对于事务日志,我指定了10GB的自动增长系数。这个的确是个不好的做法,但我只是用它来展示这个设置的副作用。请不要在你的生产数据库里使用这个错误配置!!!

-- Create a new database with 10 GB Auto Growth for the Transaction Log
CREATE DATABASE AutoGrowthTransactionLog ON PRIMARY
(
    NAME = N‘AutoGrowthTransactionLog‘,
    FILENAME = N‘C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\AutoGrowthTransactionLog.mdf‘,
    SIZE = 5120KB,
    FILEGROWTH = 1024KB
)
LOG ON
(
    NAME = N‘AutoGrowthTransactionLog_log‘,
    FILENAME = N‘C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\AutoGrowthTransactionLog_log.ldf‘,
    SIZE = 1024KB,
    FILEGROWTH = 10240000KB -- 10 GB Auto Growth!
)
GO

下一步里我在数据库里创建2个表。第1个表我通过插入一些日志来快速填充我的事务日志。在事务日志自动增长阶段,我们在第2个表里插入新的记录来证明这个事务会被自动增长机制阻塞。

-- Create a new table, every records needs a page of 8kb
CREATE TABLE Chunk
(
    Col1 INT IDENTITY PRIMARY KEY,
    Col2 CHAR(8000)
)
GO

-- Another simple table
CREATE TABLE Foo
(
    Bar INT NOT NULL
)
GO

现在我们已经创建了必须的数据库对象,因次我可以通过新的没有立即提交的事务来填充事务日志:

-- Begin a new transaction, that blocks the 1st VLF in the Transaction Log
BEGIN TRANSACTION
INSERT INTO Chunk VALUES (REPLICATE(‘x‘, 8000))
GO

因为我们现在有了进行中,没提交的事务,SQL Server不能重用那部分事务日志,即这个事务存储的事务日志。它们有需要回滚的可能。因此现在我通过不同的会话插入66条其他记录来填充事务日志:

INSERT INTO AutoGrowthTransactionLog.dbo.Chunk VALUES (REPLICATE(‘x‘, 8000))
GO 66

最后在第一个会话里提交我们的事务:

COMMIT

这意味着在我们面前有一个几乎满的的事务日志,我们可以通过DBCC LOGINFO来验证:

DBCC LOGINFO

现在当我们往表里插入兮的记录时,事务日志已经没有可用空间了,SQL Server进入事务日志的自动增长。

-- This statement will trigger the Auto Growth mechanism!
INSERT INTO Chunk VALUES (REPLICATE(‘x‘, 8000))
GO

在自动增长期间的同时,为了监控发生了什么,我们可以在SSMS里打开新的一个会话窗口,尝试在第2个表插入另外的记录——表Foo

-- This statement is now blocked by the Auto Growth mechanism.
INSERT INTO Foo VALUES (1)
GO

这个SQL 语句会阻塞,因为事务要写入事务日志记录的事务日志,当前不可用。为了进一步分析这个阻塞情形,你可以打开第3个会话窗口,执行下列2个SQL语句:

-- Analyze the blocking situation
SELECT wait_type, * FROM sys.dm_exec_requests
WHERE session_id IN (54, 55)

SELECT wait_type, * FROM sys.dm_os_waiting_tasks
WHERE session_id IN (54, 55)
GO

(额,俺本机测试失败………………)

从代码里可以看到,我用2个DMV sys.dm_exec_requests 和 sys.dm_os_waiting_tasks对2个会话都进行了跟踪——触发自动增长的会话,和被自动增长机制阻塞的会话。在这里,触发自动增长的会话里有所谓的抢占等待类型(Preemptive Wait Type)——PREEMPTIVE_OS_WRITEFILEGATHER。抢占等待类型是由SQL Server返回的等待类型,当SQL Server 执行一个WIN32 API函数在调度机制之外时。这里自动增长是通过WriteFileGather的WIN32 API函数完成的。

INSERT语句尝试在Foo表里插入新的记录出现LATCH_EX等待类型。如你从DMV sys.dm_os_waiting_tasks 里的resource_description列所见,在SQL Server的日志管理器上需要获得闩锁。你可以通过查询DMV sys.dm_os_latch_stats 限制lactch class为LOG_MANAGER再次确认。在那个特定闩锁上你会看到一些等待。那个闩锁是事务获取的,由事务日志的自动增长触发,只要这个闩锁要获得,每个其他写事务都会被阻塞。因此在系统上有大量等待时间时,这暗示这在事务日志里当前有自动增长问题需要处理。

希望我已经用这个日志说服你,依赖于事务日志的自动增长机制并不是最好的解决方案。用这个简单的例子可以看到,在你数据库里每个被自动增长操作阻塞的写入事务会发生阻塞,这肯定会伤及你数据库的吞吐量和扩展性。

时间: 2024-11-08 20:25:19

【转】为什么事务日志自动增长会降低你的性能的相关文章

为什么事务日志自动增长会降低你的性能

在这篇文章里,我想详细谈下为什么你要避免事务日志(Transaction Log)上的自动增长操作(Auto Growth operations).很多运行的数据库服务器,对于事务日志,用的都是默认的日志文件大小和自动增长设置.人们有时会很依赖自动增长机制,因为它们刚好能正常工作.当然,如果它正常工作的话,你不必太关注它,但很快你会发现会有问题出现. 只依赖于事务日志的自动增长机制总不是个好主意.首先它会导致严重的日志碎片(Log Fragmentation),在SQL Server启动期间,在

为什么事务日志会增长

正如我们之前所说的,事务日志会记录所有的数据库更改.如果你的系统比较繁忙,经常做一些数据库更改操作.这会使事务日志增长.如果我们取消了自动增长,而事务日志大小已经达到了预设的最大值,数据库系统就会报错.我们一般建议是选择自动增长,但是要持续的监视日志文件大小.当然如果设置的增长率比较小的话会影响性能.每次增长应该足够的大以防止不断的执行增加大小操作.默认的是每次增加10%, 这个应该是对大部分系统足够了.我们应该持续的跟踪日志文件的变化,日志文件增长的频率来适当的更改增长率.使用固定的增长大小(

SQL Server中的事务日志管理(7/9):处理日志过度增长

当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会告诉你每个DBA应该知道的具体细节. 这篇文章会列出导致事务日志过度增长的常见的问题和错误管理形式,包括: 在完整恢复模式里,没有进行日志备份 进行索引维护 长时间运行或未提交的事务阻止事务日志里空间重用 当然,如果增长没检查,日志文件会扩展直到吞没所有可用磁盘空间或日志文件的最大大小,在这个时候你

SQL Server 默认跟踪应用4 -- 检测日志文件自动增长

SQL Server 默认跟踪应用4 -- 检测日志文件自动增长 用户抱怨SQL Server数据库运行非常慢.通过默认跟踪的这个查询,可以识别出log file autogrow活动导致的长时间运行.为什么如此之慢? SELECT te.name AS [trace_events_name] , t.DatabaseName , t.NTDomainName , t.ApplicationName , t.LoginName , t.Duration , t.StartTime , t.End

【转】SQL Server如何截断(Truncate)和收缩(Shrink)事务日志

SQL Server如何截断(Truncate)和收缩(Shrink)事务日志分类: SQL Server数据库备份还原2010-01-25 14:321708人阅读评论(4)举报 当SQL Server截断事务日志时,它仅仅是在虚拟日志文件中做个标记,以便不再使用它,然后准备以重用形式来做备份(假如运载在完整或是批量日志恢复模型).也就是说,在使用简单恢复模型时,事务日志包括如下的日志记录: 当checkpoint发生时,虚拟日志文件1.2不再被使用,因为事务1.2已经被提交了,而且日志记录也

XenDesktop SQL Server Mirror事务日志维护

当使用SQL Server高可用性功能的时候,例如,XenDesktop站点数据库使用完整的事务日志记录模式下运行的数据库镜像. 通过完整的事务日志记录模式下运行的事务日志会增长过大,直到数据库空间被填满或事务日志空间大小被填满.如果事务日志文件不会被监视的,默认情况下,SQL Server的配置日志文件会自动增长.这将导致2个问题: 1.事务日志文件会占用大量的磁盘空间 2.事物日志增长填满数据库空间,导致数据库不可用. 因此Citrix建议定期备份日志文件.这可以通过调度作业或维护计划来完成

SQL Server如何截断(Truncate)和收缩(Shrink)事务日志

原文:http://blog.csdn.net/tjvictor/article/details/5253931 ? 当SQL Server截断事务日志时,它仅仅是在虚拟日志文件中做个标记,以便不再使用它,然后准备以重用形式来做备份(假如运载在完整或是批量日志恢复模型).也就是说,在使用简单恢复模型时,事务日志包括如下的日志记录: 当checkpoint发生时,虚拟日志文件1.2不再被使用,因为事务1.2已经被提交了,而且日志记录也不再需要回滚了.然后SQL Server重用虚拟日志文件1.2,

[SQL Server] 数据库日志文件自动增长导致连接超时的分析

1.现象.问题描述 客户反映某客户端登陆不了,客户端程序日志显示“连接数据库超时”:检查对应的数据库服务器,日志显示“Autogrow of file '某数据库日志文件' in database '某数据库' was cancelled by user or timed out after 2391 milliseconds.  Use ALTER DATABASE to set a smaller FILEGROWTH value for this file or to explicitly

[转载]C#中使用ADO.NET连接SQL Server数据库,自动增长字段用作主键,处理事务时的基本方法

问题描述: 假设在数据库中存在以下两张数据表: User表,存放用户的基本信息,基本结构如下所示:   类型 说明 ID_User int 自动增长字段,用作该表的主键 UserName varchar   UserDepart表,存放用户所拥有的部门(我们假设一个用户拥有多个部门,虽然听起来有点别扭,此处仅作示例,可以理解为一个用户拥有多个职位等等),该表的基本结构如下所示:   类型 说明 ID_UserDepart int 自动增长字段,用作该表的主键 ID_User int 用户编号 I