SQL Server日志是否记录未提交的操作?


12

我经常看到像sql server log这样的语句记录每个事务和操作。

但我感到困惑,当交易最终会发生什么 回去

说,一个明确的事务有3个语句:statement Astatement Bstatement C,最后一个rollback statement D

现在说,当执行尚未达到时rollback statement D,将statements A through C记录到sql服务器的修改结果记录到日志中吗?

理解1

语句A到D都被记录下来。无论如何,SQL Server都会记录所有内容。

理解2:修改仅存储在内存中的某个位置,并且仅在SQL Server看到一条commit语句时才记录到日志中。如果事实证明它是rollback语句,则SQL Server只会忽略事务,不会写入日志,因为它没有任何作用。换句话说,SQL Server时,有一个记录结果之前之后的交易。

两者似乎合乎逻辑,至少在我看来,但两者都不对。谢谢你的帮助。


嗨,尝试[ systoolsgroup.com/sql-log-analyzer.html](SQL日志分析器)来分析日志文件中发生的事情。您可以尝试仅预览SQL日志数据的SysTools SQL Log Analyzer的免费版本。希望这对您有用。
Rylan17年7

Answers:


13

理解1是正确的。SQL Server记录将数据更改为事务日志的每个操作。回滚是对数据的更改,因此它也将其记录到事务日志中。作为语句A运行,它将数据写入事务日志,并且还将保留事务日志中的数据,以防需要回滚语句A。B和C也是如此。回滚事务时,更多信息将被写入日志。

有很多方法可以看到此效果,因此下面是一个快速演示。这是我将用来查看写入日志的查询:

SELECT 
  COUNT(*) transaction_count
, SUM(database_transaction_log_bytes_used) used_bytes
, SUM(database_transaction_log_bytes_reserved) reserved_bytes
FROM sys.dm_tran_database_transactions
where database_id = 10;

我的桌子:

create table TLOGDEMO (FLUFF VARCHAR(1000));

BEGIN TRANSACTION

查询A使用最少的日志记录:

INSERT INTO TLOGDEMO WITH (TABLOCK)
SELECT REPLICATE('A', 1000)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

之后:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
                 1    24006640       175429451 
╚═══════════════════╩════════════╩════════════════╝

查询B不使用最少的日志记录:

INSERT INTO TLOGDEMO
SELECT REPLICATE('B', 1000)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

B之后:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
                 1  7352935708      1613986255 
╚═══════════════════╩════════════╩════════════════╝

查询C更改的数据较少:

INSERT INTO TLOGDEMO
SELECT REPLICATE('C', 1000)
FROM master..spt_values c;

C之后:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
                 1  7355821748      1614545331 
╚═══════════════════╩════════════╩════════════════╝

现在,我将发出a ROLLBACK并在回滚发生时查询DMV。以下是一些快照的表:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
 1                  7393305528  1573797677     
 1                  7458767420  1502635737     
 1                  7682482356  1259440979     
 1                  7803881368  1127471233     
 ...                ...         ...            
╚═══════════════════╩════════════╩════════════════╝

在期间ROLLBACK,使用的字节增加,保留的字节数减少。这是因为SQL Server正在使用它在撤消事务之前预留的空间。要撤消事务,它必须更改数据,以便将更多数据写入日志。


8

对数据库表的修改首先写入日志文件,然后写入表本身,首先写入内存,然后使用称为的异步过程CHECKPOINT写入磁盘。这种机制称为WAL(预写日志记录),并且在所有关系数据库中都是通用的。

日志本身首先被写入内存(精确地写入日志缓冲区),然后写入磁盘,但是在将日志写入磁盘之前,数据库表上没有任何接触。

此机制允许在恢复过程中前滚已提交的事务和回滚未提交的事务。对于您的示例,如果事后发生了不好的情况,statement C而您却使用commit了a rollback(而不是事先知道),而不保存事务中的每一步,则RDBMS将无法以一致的方式恢复数据库。方式,交易将不符合中的D(耐久性)ACID

回滚某些操作时,是数据文件(通过CHECKPOINT)接收净更改,而不是日志文件。


5

理解1是正确的,并且spaghettidba和Joe有很好的解释。

如果您有兴趣自己进行测试(请在测试实例上进行测试),则可以使用以下脚本:

--create a database and table for testing
USE master
GO
CREATE DATABASE tranlogtest
GO
USE tranlogtest
GO
CREATE TABLE t1
(junk char(1))

CHECKPOINT
GO

BEGIN TRAN
INSERT t1 VALUES ('a')
INSERT t1 VALUES ('b')
INSERT t1 VALUES ('c')

ROLLBACK
INSERT t1 VALUES ('d')

SELECT *
FROM fn_dblog(NULL,NULL)

您将看到SQL Server记录了所有内容,甚至包括撤消操作所采取的步骤。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.