设为首页 加入收藏

TOP

SQL Server中的事务日志管理(7/9):处理日志过度增长(四)
2015-11-21 01:29:37 来源: 作者: 【 】 浏览:8
Tags:SQL Server 事务 日志 管理 7/9 处理 过度 增长
要运行在完整恢复模式。如果必须要能恢复数据库到任意时间点或到灾难事件前的一个时间点,则是必须的,或者必须要用完整恢复模式的另一个原因(例如数据库镜像)。如果在SLA里目标恢复点( Recovery Point Objective (RPO) )为最大15分钟的数据丢失,那么很可能你不能只进行完整数据库备份和差异数据库备份,必须要进行日志备份。
?
但是,如果因为不需要而没有进行日志备份,那么数据库不应该运行在完整恢复模式;我们可以切换数据库到简单恢复模式,那事务日志的不活动部分会自动标记为可重用,在检查点的时候。
?
如果数据库需要运行在完整恢复模式,那么开始日志备份,或调查下备份需要的频率。事务日志的备份频率取决于很多因素,例如数据修改的频率,还有在灾 难中,SLA上可接受的数据丢失程度。另外,你应该采取措施保证日志增长是可控的,在将来是可预见的,在这篇文章里的妥当的日志管理部分会介绍。
?
活动事务
?
如果log_reuse_wait_desc的返回值是ACTIVE_TRANSACTION,那么你受到来自SQL Server里完整或大的事务日志的第二个常见原因:长时间运行或未提交的事务。重新执行下来自代码7.1的事务,但不提交,在重新执行下代码7.3,你 会看到这个值返回(不要忘记回去提交这个事务)。
?
如在第2篇日志截断和空间重用部分介绍的,事务日志里的VLF只有在不包含活动日志部分时才会被截断。如果数据库试用完整或大容量日志恢复模式,只 有日志备份操作才可以进行截断。数据库里长时间运行的事务延迟包含事务开始后生成的日志记录的VLF的截断,包括其它并发事务对数据库里的数据修改产生的 日志记录,甚至当这些改变还没提交时。另外,长时间运行的事务的空间需求量会通过对“补偿日志记录”保留的空间增加,如果在系统里事务回滚的话,这些日志 记录就会产生。这些保留是需要的,保证在回滚期间,这些事务可以成功恢复而不会用完日志空间。
?
另一个常见对log_reuse_wait_desc值的活动事务值是“孤立”的显式事务,它莫名其妙的从不提交。允许用户在事务里输入的应用程序就特别容易是这类问题。
?
长时间运行的事务
造成长时间运行的事务的最常见操作,也是在数据库里生成大量日志记录,是从数据库里归档或清除数据。数据保持往往是数据库设计里事后的想法,经常是数据库已经活跃一段时间后才考虑,是在服务器接近可用存储的容量限制。
?
通常,当需要归档时,第一个反应是从数据库里使用简单的DELETE语句删除不需要的数据,如代码7.4所示。为了生成一些简单的测试数据,这个脚本使用Jeff Moden的随机数据生成器的简化版本,简单修改来生成日期到2012。
?
USE FullRecovery ;
GO
IF OBJECT_ID('dbo.LogTest', 'U') IS NOT NULL?
? ? DROP TABLE dbo.LogTest ;
SELECT TOP 500000
? ? ? ? SomeDate = CAST(RAND(CHECKSUM(NEWID())) * 3653.0 + 37534.0 AS DATETIME)
INTO ? ?dbo.LogTest
FROM ? ?sys.all_columns ac1
? ? ? ? CROSS JOIN sys.all_columns ac2 ;
?
-- delete all but the last 60 days of data
DELETE ?dbo.LogTest
WHERE ? SomeDate < GETDATE() - 60
?
(代码7.4:大容量数据删除)
?
取决于要删除的在日期范围内存在的行数,这会变成引起日志增长问题的长时间运行的事务,即使数据库运行在简单恢复模式。外键串联约束的出现或审计触 发器会恶化问题。如果其它表引用目标表,通过外键约束来级联删除,那么SQL Server页通过级联约束来记录删除的行的细节。如果表上有DELETE触发器,在触发器执行期间,SQL Server也会记录进行的操作。
?
为了最小化在事务日志上的影响,数据清理应该简化为更短,独立的事务。有很多方法中断长时间运行的事务为小的批处理。如果表存在级别约束或DELETE触发器,我们可以在循环内进行删除操作,在一个时间删除一天的数据,如果代码7.5所示。注意,在这个简单的例子里,在我们的表里没有足够的行来验证这个技术的使用,简单的DELETE;清理几百万行数据更合适。也注意批量删除的主要关心的是并不是速度(代码7.5会比代码7.4运行更慢)。最要关心的是避免日志过度增长和锁升级。
?
DECLARE @StopDate DATETIME ,
? ? @PurgeDate DATETIME
SELECT ?@PurgeDate = DATEADD(DAY, DATEDIFF(DAY, 0, MIN(SomeDate)), 0) ,
? ? ? ? @StopDate = DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 60, 0)
FROM ? ?dbo.LogTest
?
WHILE @PurgeDate < @StopDate?
? ? BEGIN
? ? ? ? DELETE ?dbo.LogTest
? ? ? ? WHERE ? SomeDate < @PurgeDate
? ? ? ? SELECT ?@PurgeDate = DATEADD(DAY, 1, @PurgeDate)
? ? END
?
(代码7.5:将数据清除拆散为小的事务)
?
使用这个方法清除数据,每个删除事务的持续时间是从表里删除一条记录的时间,加上任何触发器或级联约束进行它们操作的时间。如果数据库使用简单恢复模式,下个检查点会截断这些清除产生的日志记录,只要在VLF里没有相关数据清理的活动日志存在。
?
当在处理过程中级联约束或审计触发器不是要考虑的,我们可以使用不同的方法来清理表上的数据,同时最小化事务。不是进行一点的DELETE操作,它会影响多少的数据,取决于指定日期里存在的行数,在DELETE语句里使用TOP运算符会限制每个循环操作影响的行数。使用@@ROWCOUNT来捕获DELETE操作影响的行数,运算符会在小的批处理语句里清除数据,直到@@ROWCOUNT的值小于DELETE语句里TOP子句里指定的行数,如代码7.6所示。
?
这个方法只有在没有触发器和级别约束时使用有效,不然的话@@ROWCOUNT的结果不是实际表删除的行数,而是触发器执行或通过强制级联约束影响的行数。
?
?1 DECLARE @Criteria DATETIME ,
?2 ? ? @RowCount INT
?3 SELECT ?@Criteria = GETDATE() - 60 ,
?4 ? ? ? ? @RowCount = 10000
?5 WHILE @RowCount = 10000?
?6 ? ? BEGIN
?7 ? ? ? ? DELETE TOP ( 10000 )
?8 ? ? ? ? FROM ? ?dbo.LogTest
?9 ? ? ? ? WHERE ? SomeDate < @Criteria
10 ? ? ? ? SELECT ?@RowCount = @@ROWCOUNT
11 ? ? END
?
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/8/8
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇SQLServer索引维护(1)――如何.. 下一篇SQL Server字段类型简介

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: