导数中的最小化日志记录:背景和理论

什么是最小化日志(Minimal Logging)

当数据库的恢复模式为SIMPLE或者BULK_LOGGED时,对于最小化日志类型的操作,事务日志不记录单独每个数据行的日志,而是记录对应页和区结构的修改日志。这样显著减少了操作产生的事务日志数量。例如,向某个数据页上插入200行数据,在最小化日志记录的情况下,只会记录一条此数据页变化的日志,而不是200条Insert日志。


最小化日志类型的操作

  • SELECT INTO
  • Bulk导数操作,包括 BULK INSERT和BCP
  • INSERT INTO . . . SELECT,包括两种情况:

    a) SELECT中使用OPENROWSET(BULK. . .) 
    b)目标表不具有非聚集索引,向其插入超过8页的数据量,并且使用了TABLOCK时。如果目标表为空,可以有聚集索引,如果不为空,则不可以。

  • 部分更新大值类型的列
  • UPDATE中使用.WRITE插入数据或追加数据时
  • 对LOB字段使用WRITETEXT和UPDATETEXT插入或者追加新数据,不包括更新。
  • 索引操作,包括在表/视图上CREATE INDEX,ALTER INDEX REBUILD,DBCC DBREINDEX,DROP INDEX(新堆的重新生成将按最小方式记录)


数据导入中的最小化日志记录

本文关注的是数据导入的最小化日志记录,指BULK INSERT导数操作。很多理论在其它类型的操作上是通用的。

1. 普通的INSERT

SQL Server中使用锁和日志记录来保证数据库事务的ACID属性。在插入一行数据的整个事务期间,为了避免并发事务访问,这一行会被锁定;同样这一行还会被写入日志记录。插入一行数据的大概的步骤如下:

  1. 通过行锁锁定行。
  2. 写入日志记录。日志记录包含被插入行的完整数据
  3. 数据行被写入数据页。

多行插入时,每一行都会重复以上步骤。这里指大概操作原型,实际处理复杂的多,如锁升级,约束检查等等

2. BULK导入

当BULK导入提交事务时,事务使用到的所有数据页会被写入磁盘,这样来保证事务原子性。相当于每次提交事务时都做一次CHECKPOINT。如果需要回滚BULK事务,SQL Server会检索日志获取事务涉及的页或者区信息,然后将之重新标记为未使用。备份事务日志时会将BULK涉及的数据页和索引页都备份到日志备份中。还原包含BULK事务的日志备份时,不支持还原到指定时间点。

每个数据文件第八个页是BCM页(BULK Chandged Map),之后每隔511230页会有一个BCM页。BCM上的每一位(Bit)代表着一个区,如果此位为1,则表示自上次BACKUP LOG后,这个区被BULK类型操作修改过。再下次日志备份时,会将这些被修改过的区复制到日志备份中。

3. 使用最小日志记录导入数据时需要满足的条件

并不是任何情况下都可以实现最小日志导数,判断逻辑如下(来自Itzik Ben-Gan)

a) SQL Server 2008之前的版本判断逻辑:

non-FULL recovery model

AND NOT replicated

AND TABLOCK

AND (

Heap

OR (B-tree AND empty)

)

b) SQL Server 2008及以后版本的判断逻辑:

Non-FULL recovery model

AND NOT replicated

AND (

(Heap AND TABLOCK)

OR (B-tree AND empty AND TABLOCK)

OR (B-tree AND empty AND TF-610)

OR (B-tree AND nonempty AND TF-610 AND key-range)

从SQL 2008开始可以使用跟踪标记610和排它键范围锁,实现空/非空聚集索引表的最小化日志操作。

排他键范围锁的作用例子:聚集索引表tb(id INT),目前有4行数据,分别为1,1000,2000,3000。现在需要向表中插入500行数据,这些数据的值区间为[1001,1500]。当插入时,SQL Server不需要获取聚集索引整体的排它锁(像tablock这种),而只是获取原有键值区间的排它键范围锁。这里就是在(1000,2000)区间上获取X KEY-RANGE LOCK。而不在这个区间的数据,仍然可以被其它进程访问。如果要实现非空索引表的最小化日志记录导数,需要预先将导入数据按目标表的索引键值列进行排序,并启用跟踪标记610。

从上面的判断逻辑可以看出,实现最小日志记录的大前提是:数据库不是完整恢复模式且表没有标记为复制。对于堆表总是需要使用TABLOCK。对于索引表,则要分为空表和非空表两种情况来处理。这部分内容在后文的例子再展开来说明。


观察BULK导入的日志

使用未公开的系统函数sys.fn_dblog查找相关的日志内容。fn_dblog接受两个参数用以指定要查询的日志区间,分别表示开始和结束的LSN。输出字段中,此文需要关注的是Operation, Context, Log Record Length和AllocUnitName。因为是未公开的的函数,所以输出内容代表的意义,需要结合个人经验和大家的“共识”来解读。

  • Operation(LOP):表示执行何种日志操作, 例如修改行为LOP_MODIFY_ROW,设置位图页时为LOP_SET_BITS等等。
  • Context(LCX):日志操作的上下文,一般表示受影响的对象类型。例如LCX_GAM,LCX_HEAP,LCX_PFS等。
  • Log Record Length:以byte为单位的日志长度
  • AllocUnitName:表示受影响的具体对象

使用如下脚本进行分析,脚本来自Jakub K

-- 日志条目录数据和总大小
SELECT COUNT(*)AS numrecords,
  CAST((COALESCE(SUM([Log Record LENGTH]), 0))
    / 1024. / 1024. AS NUMERIC(12, 2)) AS size_mb
FROM sys.fn_dblog(NULL, NULL) AS D
WHERE AllocUnitName = ‘dbo.tableName‘ OR AllocUnitName LIKE ‘dbo.tableName.%‘;
-- 各类型日志的平均长度和数量
SELECT Operation, Context,
  AVG([Log Record LENGTH]) AS AvgLen, COUNT(*) AS Cnt
FROM sys.fn_dblog(NULL, NULL) AS D
WHERE AllocUnitName = ‘dbo.destination_pk‘ OR AllocUnitName LIKE ‘dbo.destination_pk.%‘
GROUP BY Operation, Context, ROUND([Log Record LENGTH], -2)
ORDER BY AvgLen, Operation, Context;
时间: 2024-10-12 11:36:40

导数中的最小化日志记录:背景和理论的相关文章

SQL Server 最小化日志操作解析,应用[手稿]

Sql Server 中数据库在BULK_LOGGED/SIMPLE模式下的一些操作会采用最小化日志的记录方式,以减小tran log落盘日志量从而提高整体性能. 这里我简单介绍下哪些操作在什么样的情况下会最小化日志记录.以及现实生产环境中如何应用最小化日志. 概念:SQL Server在满足相应条件的基础上时进行一些特定的操作如Rebuild Index时会进行最小化Tran Log记录操作,从而改善系统性能. 注意:含最小化操作日志操作段日志无法按时间点恢复(point in time) 需

SQL Server 最小化日志操作解析,应用

Sql Server 中数据库在BULK_LOGGED/SIMPLE模式下的一些操作会采用最小化日志的记录方式,以减小tran log落盘日志量从而提高整体性能. 这里我简单介绍下哪些操作在什么样的情况下会最小化日志记录.以及现实生产环境中如何应用最小化日志. 概念:SQL Server在满足相应条件的基础上时进行一些特定的操作如Rebuild Index时会进行最小化Tran Log记录操作,从而改善系统性能. 注意:含最小化操作日志操作段日志无法按时间点恢复(point in time) 需

在 VirtualBox 中安装最小化版 CentOS

在 VirtualBox 中安装最小化版 CentOS 发表于 2013-08-27 作者 Haoxian Zeng 浏览 3,062 次 7 在刚开始接触 VPS 服务器的时候,为了测试各种程序和配置是否能用,就在本地使用 VirtualBox创建了一个与 VPS 配置差不多一样的虚拟机,也装上了 Linux 的 CentOS 发行版,内存大小.系统和软件都照着 VPS 的模式来.这是个练手的好方法. 因为只是将它当作一个 VPS 来用的,安装之前考虑这么几件事情: 操作系统.Linode V

[转]asp.net5中使用NLog进行日志记录

本文转自:http://www.cnblogs.com/sguozeng/articles/4861303.html asp.net5中使用NLog进行日志记录 asp.net5中提供了性能强大的日志框架,本身也提供了几种日志记录方法,比如记录到控制台或者事件中等,但是,对大部分程序员来说,更喜欢使用类似log4net或者Nlog这种日志记录方式,灵活而强大.asp.net5中也包括NLog的实现,下面把最简单的使用方法写出来,抛砖引玉,让更多对此不熟悉的同学们能借此入门. 1.在project

asp.net5中使用NLog进行日志记录

asp.net5中提供了性能强大的日志框架,本身也提供了几种日志记录方法,比如记录到控制台或者事件中等,但是,对大部分程序员来说,更喜欢使用类似log4net或者Nlog这种日志记录方式,灵活而强大.asp.net5中也包括NLog的实现,下面把最简单的使用方法写出来,抛砖引玉,让更多对此不熟悉的同学们能借此入门. 1.在project.json中添加对Microsoft.Framework.Logging.NLog的引用,目前最新是beta8版本: 2.然后添加NLog.config配置文件到

在android中配置 slf4j + log4j 日志记录框架

需求: 在项目开发中,需要记录 操作日志 .起初自己写了个简单的日志记录文本写入到文本的方法,后来随着项目的膨胀,需要考虑更多的操作,开始考虑性能问题. 实现: 考虑使用 slf4j + log4j 框架来实现.slf4j 是日志记录的一个facade,支持多种日志框架.log4j是个很优秀的日志记录框架. 实现: 下载类库: 先到各主站点下载类库 slf4j 网址 :http://www.slf4j.org/download.html log4j网址: http://logging.apach

在asp.net core的项目中通过log4net添加日志记录到本地文件

=============================================== 2020/2/25_第1次修改                       ccb_warlock =============================================== 由于之前的时间都忙于项目的业务开发,对于log4net的使用一直是“拿来主义”,仅仅用在了调试时输出到控制台看结果,而没有深究配置文件的参数和具体的机制. 正巧这段时间项目进度没有那么紧张,我也有时间来完善框

Python 中更优雅的日志记录方案

---恢复内容开始--- 阅读本文大概需要 5 分钟. 在 Python 中,一般情况下我们可能直接用自带的 logging 模块来记录日志,包括我之前的时候也是一样.在使用时我们需要配置一些 Handler.Formatter 来进行一些处理,比如把日志输出到不同的位置,或者设置一个不同的输出格式,或者设置日志分块和备份.但其实个人感觉 logging 用起来其实并不是那么好用,其实主要还是配置较为繁琐. 常见使用 首先看看 logging 常见的解决方案吧,我一般会配置输出到文件.控制台和

php项目中常用的log日志记录方法

/** * ****************** * 1.写入内容到文件,追加内容到文件 * 2.打开并读取文件内容 * ******************* */ function save_log($path, $msg) { if (! is_dir($path)) { mkdir($path); } $filename = $path . '/' . date('YmdHi') . '.txt'; $content = date("Y-m-d H:i:s")."\r