检查点(Checkpoint)过程如何处理未提交的事务

每次我讲解SQL Server之前,我都会先简单谈下当我们执行查询时,在SQL Server内部发生了什么。执行一个SELECT语句非常简单,但是执行DML语句更加复杂,因为SQL Server要修改内存中的相关页,并在事务日志里记录整个事务。

介绍完这些特定步骤后,我总会问同样的问题:当我们有个未提交的事务,这个时候刚好有检查点(Checkpoint)发生,SQL Server会崩溃么?在我们数据文件里有我们未提交的数据么?先思考下,然后再写下你的答案。

创建测试场景

现在我想和你一起重建这个特定场景,最后你会看到你是否回答对了。这个场景的第一步,我创建了一个新的数据库,一个新的表,并插入一些记录。

 1 -- Create a new database
 2 CREATE DATABASE Checkpointing
 3 GO
 4
 5 -- Use it
 6 USE Checkpointing
 7 GO
 8
 9 -- Create a new table
10 CREATE TABLE Foo
11 (
12     Col1 CHAR(100) NOT NULL,
13     Col2 CHAR(100) NOT NULL,
14     Col3 CHAR(100) NOT NULL
15 )
16 GO
17
18 -- Insert a record
19 INSERT INTO Foo VALUES
20 (
21     REPLICATE(‘A‘, 100),
22     REPLICATE(‘B‘, 100),
23     REPLICATE(‘C‘, 100)
24 )
25 GO
26
27 -- Retrieve the record
28 SELECT * FROM Foo
29 GO

在我们插入数据后,我想知道SQL Server存储特定记录的页号。我们可以使用DBCC IND命来来返回特定表的所有页。在我的服务器上SQL Server使用的Page id是79。

1 -- Retrieve the first data page for the specified table (columns PageFID and PagePID)
2 DBCC IND(Checkpointing, Foo, -1)
3 GO

现在当我们用DBCC PAGE命令输出页内容时(使用这个命令前,要先启用3604跟踪标记),我们可以看到插入的A,B,C的16进制值。

1 -- Enable DBCC trace flag 3604
2 DBCC TRACEON(3604)
3 GO
4
5 -- Dump the first data page of the table Customers retrieved by DBCC IND previously
6 DBCC PAGE (Checkpointing, 1,79, 3)
7 GO

现在当我们进行检查点(Checkpoint)过程,并最终杀掉SQL Server会发生什么?未提交的数据会物理写入数据文件么?我们来试验下...

崩溃并恢复SQL Server

现在我们开始一个新的事务,并更新插入记录的第一列。

1 -- Begin a new transaction without committing it...
2 BEGIN TRANSACTION
3
4 UPDATE Foo
5 SET Col1 = REPLICATE(‘X‘, 100)

从代码里你可以看到,我们并没有提交这个事务!它还是待定的,未提交的事务。现在我们打开另一个会话,我们人为进行一次检查点(Checkpoint)过程,并最终关闭SQL Server。

1 -- Execute it in a different session
2 CHECKPOINT
3 GO
4
5 SHUTDOWN WITH NOWAIT
6 GO

现在你认为未提交的事务已经写入数据文件了么?不确定?我们来找出答案!我们在16进制的编辑器(例如XVI32)里打开数据文件。跳到页号79的开始。在数据文件里,页号是物理偏移量,即页开始的地方——乘上8192字节,因为在SQL Server里页的大小是8kb。因此页79的开始整数偏移量是647168(79*8192).当我们查看hex值时,我们看到了我们未提交的数据。

检查点(Checkpoint)过程不会区分提交和未提交的事务。它只会到缓存管理器(Buffer Manager)索取所有脏页,不管它们事务的状态。

现在我们有不一致,损坏的数据库了么?没有,并不真的是。因为现在当我们启动SQL Server,每个数据库都经过故障恢复阶段,所有没提交的事务都会回滚。当SQL Server启动的时候,我们可以在SQL Server日志里看到这个行为:

小结

检查点(Checkpoint)不会在意你的事务状态。来自缓存池(Buffer Pool)的每个脏页会写入数据页。如果SQL Server崩溃了也没关系,因为故障恢复能恢复你的数据库到完全一致的状态。我希望这篇日志能让你更好的理解检查点(Checkpoint)过程,还有它如何与未提交的事务打交道。

作为家庭作业,你能否留言告诉我,还有哪些情形,SQL Server需要运行故障恢复为你的数据库还原到一致状态。在SQL Server里你知道多少个不同的场景呢?

参考文章:https://www.sqlpassion.at/archive/2016/01/25/how-the-checkpoint-process-deals-with-uncommitted-transactions/

时间: 2024-10-05 15:25:37

检查点(Checkpoint)过程如何处理未提交的事务的相关文章

sql 查看 锁定的表 或者 未提交 的事务

--查看锁定的 表select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName from sys.dm_tran_locks where resource_type='OBJECT' --查看数据库IDselect DB_ID()--查看 未提交的事务select * from sys.dm_tran_locks where resource_type = 'OBJECT' and reso

查找mysql中未提交的事务

1.查找未提交事务 在mysql中运行: 1 select t.trx_mysql_thread_id from information_schema.innodb_trx t 2.删除线程 kill  1569831

mysql事务未提交导致锁等待如何解决

1.实验环境 Myql版本5.7.17-log 实验表结构 ([email protected])[apex]> show create table test; +-------+-----------------------------------------------------------------------------------------------------------------------------------+ | Table| Create Table      

SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因

原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中的事务概念,ACID 原则,事务中常见的问题,问题造成的原因和事务隔离级别等这些方面的知识好好的整理了一下. 其实有关 SQL Server 中的事务,说实话因为内容太多, 话题太广,稍微力度控制不好就超过了我目前知识能力范围,就不是三言两语能够讲清楚的.所以希望大家能够指出其中总结的不足之处,对我

曲苑杂坛--DML操作中如何处理那些未提交的数据

对数据库稍有了解的人,数据库使用排他锁X锁来避免两个事务同时修改同一条数据,同时使用较低级别如行上加锁来提高并发度. 以下了两种场景很容易理解: 1>事务1执行 UPDATE TB1 SET C2=1 WHERE C1=1(此处假设C1为主键,使用行锁),事务1未提交,而后事务2执行UPDATE TB1 SET C2=2 WHERE C1=1,事务2必须等到事务1提交或回滚后,才能获得对该行数据的X锁: 2>事务1执行 UPDATE TB1 SET C2=1 WHERE C1=1(此处假设C1

找出未提交的MySQL线程/事务

找出未提交的MySQL线程/事务: SELECT trx_id,trx_state,trx_started,trx_mysql_thread_id,CURRENT_TIMESTAMP - trx_started AS RUN_TIME from information_schema.innodb_trx; SELECT * from information_schema.processlist;   这个能看到上面哪个SQL线程ID(下图的378号线程就是造成MDL锁的罪魁祸首) SELECT

事务隔离级别区分,未提交读,提交读,可重复读

事务隔离超通俗好懂的的讲解 按照隔离的级别由低到高,越高的隔离,效率越差 0).DEFAULT 默认隔离级别,由数据库的数据隔离级别确定隔离级别       1).READ_UNCOMMIYTTED 都未提交的 级别最低             允许别的事务,去读取这个事务为提交之前的数据             缺点:可能会造成脏读.幻读.不可重复读.             例子讲解:店家对1000元商品进行降价500处理,数据更改,但未提交事务:             然后你查到降价将货

同一个事务里 查询 已删除但是未提交的数据[bug记录]

前几天犯了个低级错误,在一个事务方法里老是查询不到某条记录,但是debug卡住时,用db工具查,又能查出值. 经过一番折腾,原来是我在同一个事务里 查询 了已删除但是未提交的数据,当然查询不到了!!! 情况是这样的: Service层(spring事务管理配置在这一层,此方法配了PROPAGATION_REQUIRED)有个方法function m()写得很长, 其中有2步是 1. delete from B where objectid ='TestB' 2. select * from A

SQLServer之创建事务未提交读

未提交读注意事项 使用 SET TRANSACTION ISOLATION LEVEL 指定会话的锁定级别. 一次只能设置一个隔离级别选项,而且设置的选项将一直对那个连接始终有效,直到显式更改该选项为止. 事务中执行的所有读取操作都会在指定的隔离级别的规则下运行,除非语句的 FROM 子句中的表提示为表指定了其他锁定行为或版本控制行为. 事务隔离级别定义了可为读取操作获取的锁类型. 在事务进行期间,可以随时将事务从一个隔离级别切换到另一个隔离级别,但有一种情况例外. 即在从任一隔离级别更改到 S