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

12 sql-server

我经常看到sql server log之类的语句记录了每一个交易和操作。

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

假设一个显式事务有 3 个语句:statement A, statement B, statement C,最后是 a rollback statement D

现在说当执行还没有到达时rollback statement D,是否statements A through C会记录到sql server日志中产生的修改?

理解1

语句 A 到 D 都被记录下来。无论如何,SQL Server 都会记录一切。

理解二:修改只存储在内存中的某处,只有在SQL Server看到commit语句时才记录到日志中。如果结果是一个rollback语句,SQL Server 会简单地忽略事务,不会写入日志,因为它没有任何用途。换句话说,SQL Server时,有一个记录结果之前之后的交易。

两者似乎都合乎逻辑,至少对我而言,但它们不可能都是对的。谢谢你的帮助。

Joe*_*ish 12

理解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;
Run Code Online (Sandbox Code Playgroud)

我的表:

create table TLOGDEMO (FLUFF VARCHAR(1000));

BEGIN TRANSACTION
Run Code Online (Sandbox Code Playgroud)

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

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

之后:

???????????????????????????????????????????????????
? transaction_count ? used_bytes ? reserved_bytes ?
???????????????????????????????????????????????????
?                 1 ?   24006640 ?      175429451 ?
???????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

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

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

B后:

???????????????????????????????????????????????????
? transaction_count ? used_bytes ? reserved_bytes ?
???????????????????????????????????????????????????
?                 1 ? 7352935708 ?     1613986255 ?
???????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

查询 C 更改较少的数据:

INSERT INTO TLOGDEMO
SELECT REPLICATE('C', 1000)
FROM master..spt_values c;
Run Code Online (Sandbox Code Playgroud)

C之后:

???????????????????????????????????????????????????
? transaction_count ? used_bytes ? reserved_bytes ?
???????????????????????????????????????????????????
?                 1 ? 7355821748 ?     1614545331 ?
???????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

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

???????????????????????????????????????????????????
? transaction_count ? used_bytes ? reserved_bytes ?
???????????????????????????????????????????????????
? 1                 ? 7393305528 ? 1573797677     ?
? 1                 ? 7458767420 ? 1502635737     ?
? 1                 ? 7682482356 ? 1259440979     ?
? 1                 ? 7803881368 ? 1127471233     ?
? ...               ? ...        ? ...            ?
???????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

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


spa*_*dba 7

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

日志本身首先写入内存(准确地说是日志缓冲区),然后写入磁盘,但在日志写入磁盘之前,不会对数据库表进行任何操作。

这种机制允许在恢复过程中前滚已提交的事务和回滚未提交的事务。关于您的示例,如果之后发生了不好的事情statement C并且您有一个commit而不是一个rollback(您不能提前知道这一点),如果不保存事务中的每一步,RDBMS 将无法以一致的方式恢复数据库方式和交易将不满足D(持久性)中的ACID

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