下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

SqlServer存储引擎——数据库如何读写数据?

作者:课课家教育     来源: http://www.kokojia.com点击数:2093发布时间: 2017-06-08 15:00:08

标签: 数据库SqlServer数据存储

  在SQLServer数据库中,数据是如何被读写的?日志里都有些什么?和数据页之间是什么关系?数据页又是如何存放数据的?索引又是用来干嘛的?

  一起看看SQLServer的存储引擎。

  一、SQLServer的存储引擎

  大致分为以下几部分:

  1.数据库如何读写数据

  2.内存

  3.日志

  4.数据

  5.索引的结构和分类

  6.索引的遍历和维护

  下面一一详细介绍:

  1.数据库如何读写数据

  1.1 SQL Server作为一个关系型的数据库,自然也维持了事务的ACID特性,数据库的读写冲突由事务的隔离级别控制。无论有没有显式开启事务,事务都是存在的。

 SqlServer存储引擎——数据库如何读写数据?_数据库_SqlServer_数据存储_课课家教育

  (0)事务开始

  (0.1)所有DML语句必然是基于事务的,如果没有显式开启事务(SQLSERVER默认不开启隐式事务,这点与Oracle正好相反),则事务处理的最小单位为每一条DML语句,即每条语句作为一个事务,并自动提交事务;

  (0.2)除非手动开启一个事务(BEGINTRAN),或开启隐式事务(SETIMPLICIT_TRANSACTIONSON),才需要手动提交事务(COMMITTRAN),否则SQLSERVER自动提交事务;

  (1)发起DML

  (1.1)DML语句包括:INSERT、DELETE、UPDATE;

  (1.2)DDL语句最终是被转化为对系统表的DML,在SQLSERVER中DDL语句也可以被回滚(ORACLE不可以),比如:CREATE/ALTER/DROP/TRUNCATE,另外DCL语句也可以被回滚;

  (2)数据是否在内存

  (2.1)在内存中查找数据使用HASH算法,不多说;

  (2.2)如果数据页不在内存中,则需要从磁盘上的数据文件中,读取相应的数据页到内存中,即物理读,以2.1的方式查找数据页(哪怕没找到),即逻辑读。

  (3)修改数据

  (3.1)在SQLSERVER内存的数据缓冲区中将数据页修改,此时数据页称为脏页(DIRTYPAGE);

  (3.2)在SQLSERVER内存的日志缓冲区中记录REDOLOG,姑且称为脏日志;

  (4)事务结束

  (4.1)提交(COMMIT),此时将当前事务的脏日志刷新到数据库的日志文件中,并打上事务结束标记(COMMIT),脏页有可能暂未被刷新到数据文件;

  事务日志结构如下:

(4.1)提交(COMMIT),此时将当前事务的脏日志刷新到数据库的日志文件中,并打上事务结束标记(COMMIT),脏页有可能暂未被刷新到数据文件;    事务日志结构如下:

  (4.2)回滚(ROLLBACK),此时读REDOLOG(当中包括逻辑操作、或数据前后像)得到反向DML操作,反向修改脏页,将DML+反向DML从日志缓冲区刷新到数据库的日志文件中,并打上事务结束标记(ROLLBACK),同样,脏页有可能暂未被刷新到数据文件;

  事务日志结构如下:

(4.2)回滚(ROLLBACK),此时读REDOLOG(当中包括逻辑操作、或数据前后像)得到反向DML操作,反向修改脏页,将DML+反向DML从日志缓冲区刷新到数据库的日志文件中,并打上事务结束标记(ROLLBACK),同样,脏页有可能暂未被刷新到数据文件;    事务日志结构如下:

  不难发现,SQLSERVER的日志容易成为一个瓶颈(BOTTLENECK),因为在写的同时引入了读,即引入了竞争,而ORACLE用UNDOSEGMENT很好地避免了这个问题,REDOLOG永远只是在被串行写。

  (5)刷新数据页

  (5.1)SQLServer数据库遵循预写日志(WAL:Write-AheadLogging)原则,因为关系型数据库是基于事务的,而日志正是事务ACID特性的保证,也是数据恢复的保证。

  (5.2)检查点(Checkpoint),检查点周期性的将脏页刷新到数据库的数据文件中,最终在日志文件上打上检查点标记(Checkpoint),至此上面事务中修改的数据被正式写入到磁盘上的数据文件中。

  2、数据读写流程深入

  试想:

  (1)日志是不是一定要在COMMIT后才写到日志文件?如果有个很长很大的事务,那么提交日志时,日志从缓冲区被写入磁盘,岂不是要等很久?

  (2)数据是不是一定要在日志提交后,发生了CHECKPOINT,才写到数据文件?如果日志一直没提交,那么数据缓冲区岂不是很拥挤?

  考虑到这2点,SQLServer还会通过LogWriter/LazyWriter不定时的刷新日志/数据到磁盘,至于日志和数据的一致性,在启动或者数据库还原时,SQLServer会去做检查,也即是我们常说的前滚(REDO)和回滚(UNDO)。

考虑到这2点,SQLServer还会通过LogWriter/LazyWriter不定时的刷新日志/数据到磁盘,至于日志和数据的一致性,在启动或者数据库还原时,SQLServer会去做检查,也即是我们常说的前滚(REDO)和回滚(UNDO)。

  (0)SQLSERVERMEMORY

  (0.1)SQLSERVER占用服务器内存的一部分,非SQLSERVER占用的内存,供操作系统及服务器上其他应用程序使用;

  (0.2)SQLSERVER内存结构可分为两大块,关于内存结构详见《SQLServer存储引擎(2)-内存》,图中仅标出BufferPool中的数据及日志缓存;

  (1)事务结束

  (1.1)事务结束的前提是日志缓存成功写入到日志文件中,此时,数据库才会返回事务结束的响应;

  (1.2)日志缓存并不是一定要等到事务结束时才刷新到日志文件的,请看下面的234;

  (2)LOGWRITER

  (2.1)当遇到长事务时,不必等到发出事务结束命令,LOGWRITER也会周期性地将脏日志刷新到日志文件,以保证用户发出COMMIT时快速响应并结束;

  (2.2)微软并没有公布SQLSERVER除去COMMIT外,LOGWRITER将脏日志刷新到日志文件的周期,这里可以参考ORACLE的:每3秒;日志缓冲区1/3满或已经包含1M的脏日志;

  (3)LAZYWRITER

  (3.1)LAZYWRITER周期性扫描缓存(默认1s),维护自由页面列表,根据LRU算法将非脏页释放;

  (3.2)如果是脏页则刷新到磁盘,同样也是先将脏日志刷新到日志文件中,然后再将脏页刷新到数据文件中,最终内存页释放并加入自由页面列表;

  (4)CHECKPOINT

  (4.1)CHECKPOINT同LAZYWRITER一样也会刷新脏页到数据文件中,但不会维护内存自由页面列表;

  (4.2)可以设置SP_CONFIGURE‘RECOVERYINTERVAL’选项来改变CHECKPOINT发生的频率。

  小结:

  可以发现,数据和日志被写入数据/日志文件,并不是同步的。有可能写入/提交了日志,数据没有写入磁盘;有可能写入了数据,事务未被提交;

  (1)针对有完整事务日志,数据未被写入磁盘的情况,启动/还原数据库时,SQLSERVER做前滚(REDO);

  (2)针对有数据写入数据文件,日志未完整提交的事务,启动/还原数据库时,SQLSERVER做回滚(UNDO)。

  小编结语:

  更多内容尽在课课家教育!

赞(27)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程