热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SQLSERVER日志写入原理浅析

昨天看到网上有一个关于SQLSERVER课件,便随手下载了下来看看主要讲了些什么内容,于是看到了下面两个PPT页面由于第一张PPT上的内容不太准确(日志文件中没有“日志页”的概念,

   昨天看到网上有一个关于SQL SERVER 课件,便随手下载了下来看看主要讲了些什么内容,于是看到了下面两个PPT页面

    技术分享图片

技术分享图片

 

    由于第一张PPT上的内容不太准确(日志文件中没有“日志页”的概念,只有VLF的概念,可能是我们对“数据页”的概念太深刻了,因此弄了以“日志页”的概念出来,而PPT中说先更新高速缓冲区中的数据页,然后将事务日志写入到“日志页”,很容易让人理解成先更改高速缓冲区,然后将日志写入到磁盘上的“日志页”),再加上我看PPT时比较"囫囵"(只看到前一张PPT,没有往后翻两下看后面一张PPT).因此我觉得PPT的作者在日志的写入顺序上有问题.索性查了一下资料,然后比较深入的思考了日志的写入顺序问题,同时也纠正了一些自己以往的不正确理解.

    该文主要包含以下内容:
     1.SQL SERRVER 日志管理器的大致工作内容与原理.
     2.实例探究SQL SERVER 事务日志的产生与写入磁盘磁盘. 
     3.一些其它的相关思考.

    第一部分:SQL SERVER 日志管理器的大致工作原理. 

    日志管理器承担着事务日志的编排与写入工作。它维护着一个或多个被称之为“日志缓存”的连续的专用内存区域。由于SQL SERVER 事务日志必须按照一定的格式写入到日志文件中,因此日志缓存中的功能之一就是用来编排日志的格式。而当一个日志缓存区域被占满的时候,还有一个或多个日志缓存区域可以被用来保存新产生的日志记录。 
    其次,日志管理器维护着两个日志缓存队列,一个flushQueue,另一个是freeQueue。其中flushQueue包含的是等待被刷新到日志文件(物理磁盘)的日志缓存;freeQueue包含的是已经被刷新并且可以被再次使用的日志缓存。 
    而日志的刷新工作主要一个被称之为“日志编写器”的线程来负责,它将依次遍历 flushQueue,一次仅将一个当前的日志缓存中的内容写入到磁盘上。 
    而日志编写器的刷新工作由什么来触发呢?当一个事务被提交时或者日志缓存被占满时,当前的日志缓存就被放入flushQueue,日志编写器就必须开始工作。日志编写器的工作完成后, 日志管理器将会收到一个写入成功的信号,进而激活所有正在等待日志缓存刷新的所有进程,以继续完成工作。

    第二部分:实例探究SQL SERVER 事务日志的产生与写入磁盘。

    当一个更新语句被发出并获得相关锁以后,SQL SERVER 将先更改高速缓冲区中的相关数据页,在更改高速缓冲区中的页时,将会产生一条日志记录并放到日志缓存中,当这个更新语句被提交(COMMIT)时,这条存在于当前日志缓存中的日志记录将首先被成功刷新到磁盘上的日志文件中以后,再返回“更新成功”的确认信息到客户端。以上是事务比较“小”的时候日志写入的相关情况。而当事务比较“大”时,尽管事务没有被COMMIT,而日志也会被写入到磁盘上。 
   下面我将以实例来证明以下几种情况: 
    A. 当事务比较“小”时,只有事务被COMMIT时,日志才会被写入到磁盘上的日志文件中。 
    B. 当事务比较“大”时,尽管事务没有被COMMIT,日志也会被写入磁盘上的日志文件中。

    实例一:要证明情况A比较麻烦,因为需要在事务被开始但没有被COMMIT时,查看磁盘上的日志文件中是否有相关的日志记录。而SQL SERVER 虽然提供了一个未公开的查看日志记录的命令DBCC LOG(数据库名),但是这个命令却会将存在于日志缓冲区内没有实际写入磁盘的日志记录一并列出来。因此我不得不借助一个大家熟知的第三方工具Log Explorer。

    试验步骤: 
    1.建立一个测试数据库northwind,恢复模式为完整。并且对其进行一次完整备份(这样SQL SERVER 才能将日志保存,否则将会被定期截断),运行CHECKPOINT命令,然后再进行一次事务日志备份以截断所有不活动的日志。运行一下命令DBCC LOG(northwind)看看情况。  
        技术分享图片 
   在上图的结果中,你将只能看到Operation分别为LOP_BEGIN_CKPT和LOP_END_CKPT的两条日志。这两条日志是刚刚进行“事务日志备份”而产生的两条日志,而其它的日志已经被截断。 

   2.测试数据库中建立一个表TEST(ORDER_ID INT,ZDESC   VARCHAR(100) ),然后插入一条测试数据。 


技术分享图片

 CREATE TABLE TEST 
    ( 
       ORDER_ID    INT, 
       ZDESC         VARCHAR(100) 
     ) 

 GO 

   INSERT INTO TEST(ORDER_ID,ZDESC)  
                  VALUES( 1,’a’) 
  GO  
技术分享图片


    成功执行后,我们再运行DBCC LOG(northwind)看看日志的情况: 
    技术分享图片       

  

   3.然后我们运行以下命令:

         BEGIN TRAN 
              UPDATE TEST SET ZDESC=’B’ 
              WHERE ORDER_ID=1

      该命令开始了一个事务,将ZDESC列的值更改为‘B’,但是该事务没有被COMMIT.  
      运行DBCC LOG(northwind)查看日志的情况。 
   技术分享图片 
   大家注意看第54条日志,从第54条日志开始,就是我们运行上面的UPDATE事务所产生的所有日志,由于该事务并没有被COMMIT,我们必须想办法查看自54号日志开始的所有日志是否已经保存到了磁盘的日志文件中。这时,我们先将SQL SERVER服务改为手动启动,然后强行重新启动电脑,启动电脑后,在SQL SERVER未启动以前,拷贝northwind的日志文件到其它目录(虽然我们可以在电脑启动后,SQL SERVER 服务启动以后再次运行DBCC LOG(northwind)来查看日志的情况,但是我担心SQLSERRVER在启动的时候会进行恢复工作而对没有提交的日志进行什么处理),我们还是利用Log Explorer来查看拷贝出来的日志文件中的日志记录。 
   我们还是先DBCC LOG(northwind)看看情况: 
   技术分享图片 
  大家可以看到,先前的序号64,65号日志已经看不到了,而这两条日志,就是UPDATE语句产生的真正的日志,而54-63是进行修改工作系统内部的一些事务。然后我们再用Log Explorer来看看之前拷贝出来的日志文件中的日志。 
技术分享图片

    上图是Log Explorer显示的备份出来northwind的日志文件的详细情况,我们可以在上面的表格栏选中某一条日志,然后注意红色框框出来的LSN.LSN:36:87:1这条日志即是我们用DBCC LOG(northiwind)命令所显示的排序为64的即CurrentLSN为:00000036:00000087:0001这条日志,很明显,Log Explorer显示的这条日志和先前DBCC LOG(northiwind)显示出的日志并不相同,因此我们可以断定,一个“小”的事务在未被COMMIT以前,日志已经产生,并且存储在日志缓冲区,但没有写入到磁盘的日志文件中。而一旦该事物被COMMIT,日志将一定会被写入磁盘,这种情况各位园友可以自己去实际验证。 


实例二:证明情况B比较简单,我们只需要让SQL SERVER运行一个较“大”的事务,然后观察磁盘上日志文件有没有被自动增长,如果增长了,那么日志肯定被写入到磁盘上了。 

实验步骤: 
1.观察northiwind当前日志文件的大小。因为我的northwind是刚刚新建的数据库,日志文件的物理大小为1M. 
2.运行以下脚本,然后在观察日志文件的物理大小。 


技术分享图片

   BEGIN TRAN 
       DECLARE @I  INT 
       SET @I=1 
       WHILE(@I<99999) 
            BEGIN 
                 UPDATE TEST SET ZDESC=LEFT(NEWID(),10) 
                 SET @I=@I+1 
            END 
技术分享图片


  该脚本被封装成一个事务,并且没有被提交(COMMIT),运行完成后,我观察到的日志文件的物理大小为38.3M,如下图: 
技术分享图片 
很明显,尽管该事务没有被提交(COMMIT),但是,只要日志缓冲区被填满,日志缓存中的日志就会被写入到物理磁盘上。及时我们回滚了该事务,我们依然可以用DBCC LOG(northwind)看到这些被回滚的日志。 


第三部分:其它一些相关问题的思考 
    1.当SQL SERVER修改高速缓冲区中的数据页时,日志便会产生,并放入到日志缓存。那么日志究竟是由缓冲区管理器产生后交给日志管理器,还是由日志管理器探测到缓冲区的修改,然后自己产生日志。 
    2.日志缓冲中的日志,究竟要“编排”成什么格式?是否就是我们通过DBCC LOG(northwind)所看到的格式。 
    3.日志编写器在讲日志写入磁盘时,如何知道该写到日志文件的哪一个VLF,也就是说它是如何知晓某个VLF是逻辑上的最后一个VLF。

 

后文

关于Virtual Log Files(虚拟日志文件)参考这里

关于Write-Ahead Logging (预写日志)参考这里

转自:https://www.cnblogs.com/zhouqiang52154/archive/2009/06/20/1507488.html

 


推荐阅读
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
author-avatar
mobiledu2502887333
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有