我试图了解为什么下面的代码要写入日志文件。我是个初学者,已经读过了,日志不是在数据库处于简单恢复模式时编写的。但是下面的代码是在完全恢复模式和简单恢复模式下编写的。在哪种情况下,日志文件是用简单的恢复模式编写的?
代码:
Declare @val int =1
set nocount on
BEGIN TRAN
while @val <= 100000
begin
insert into LoadTable values (REPLICATE('P',1000))
set @val = @val + 1
end
ROLLBACK TRAN发布于 2016-07-26 13:07:54
首先,您的理解是,在数据库处于简单恢复模式时,不会将任何内容写入日志文件,这是错误的。
SQL Server在所有恢复模式下写入日志文件,唯一的区别是在简单恢复模式中,它会自动回收日志空间(如果可能的话),并记录维护事务的最少内容(如果您必须回滚事务)。
然而,在完全恢复模式下,我们必须进行事务日志备份,以便为SQL Server提供空间,以便用于进一步的日志记录。
现在回到您的例子:
Declare @val int =1
set nocount on
BEGIN TRAN --<-- Your Transaction starts here
while @val <= 100000
begin
insert into LoadTable values (REPLICATE('P',1000))
set @val = @val + 1
end
ROLLBACK TRAN --<-- Your Transaction ends here 在您的示例中,在事务开始之后,在事务结束之前( rollback /commit)有很多活动正在进行,如果您决定像以前一样回滚事务,那么SQL Server需要记录此活动,因此会有越来越多的日志被写入日志文件,直到事务完成(提交或回滚)。
在这个特定的例子中,server必须保存100000 insert语句的日志,以防出问题。
另一个稍微不同的查询版本可能是..。
Declare @val int =1
set nocount on
while @val <= 100000
begin
BEGIN TRAN --<-- Your Transaction starts here
insert into LoadTable values (REPLICATE('P',1000))
ROLLBACK TRAN --<-- Your Transaction Ends here
CHECKPOINT;
set @val = @val + 1
end现在,在相同的to命令的这个略有不同的版本中,在事务开始后和事务完成之前,进行的活动要少得多,因此sql server必须记录很少的数据,如果有的话,事务文件将增长很小。
在本例中,sql server必须一次只保留一个insert语句的日志,因为在该语句之后提交或回滚。
发布于 2016-07-26 14:22:14
我从Pro SQL Server 2014获取了这里的所有信息
https://www.amazon.com/Pro-Server-Internals-Dmitri-Korotkevitch/dp/1430259620
TL;DR;
恢复模式简单和完全不同的是Server将如何禁用虚拟日志文件(VLF)。
总结如下:
1-“在简单恢复模型中,事务日志的活动部分以VLF开始,其中包含最古老的活动事务的LSN或最后一个检查点”;
2-“在完整或大容量日志恢复模型中,事务日志的活动部分以VLF开始,其中包含以下最古老的内容:
上一次日志备份的LSN
最老活动事务的LSN
读取事务日志记录的进程的LSN“
LSN =日志序列号=唯一的自动递增ID
更详细的解释
假设这是Server内存模型:
缓冲区池是Server存储索引、行等的位置.在记忆中;
2-日志缓冲区是事务日志的一个小缓冲区(每个数据库64 is );
数据文件是Server将持久化索引、行等的地方.在磁盘中;
4-事务日志is...well,事务日志在磁盘中。
假设我们有一个处于以下状态的数据库。
/--------------- IN MEMORY --------------\/------------ IN DISK -----------\
|--------------------------------------------------------------------------|
|Buffer Pool | Log Buffer | Data File |Transaction Log |
|---------------------------|-------------|---------------|----------------|
|Page 1:24312 | |Page: 1:24312 |LSN:7213 |
|IsDirty: False | |LSN: 4845 | |
|LSN: 4845 | |Page: 1:24313 | |
|... | |LSN: 2078 | |
|Page 1:26912 | |... | |
|isDirty:False | |Page: 1:26911 | |
|LSN:1053 | |LSN: 2078 | |
| | |Page: 1:26912 | |
| | |LSN: 2078 | |
|---------------------------|-------------|---------------|----------------|现在假设进行了更改,这是一个简单的更新。
第一步是在日志缓冲区中插入日志记录。
/--------------- IN MEMORY --------------\/------------ IN DISK -----------\
|--------------------------------------------------------------------------|
|Buffer Pool | Log Buffer | Data File |Transaction Log |
|---------------------------|-------------|---------------|----------------|
|Page 1:24312 |LSN:7214 |Page: 1:24312 |LSN:7213 |
|IsDirty: False |Op:Update |LSN: 4845 | |
|LSN: 4845 |Page:1:24312 |Page: 1:24313 | |
|... |OldLsn:4845 |LSN: 2078 | |
|Page 1:26912 |Row:2 |... | |
|isDirty:False |Tran:T1 |Page: 1:26911 | |
|LSN:1053 |PrevLSN:7141 |LSN: 2078 | |
| | |Page: 1:26912 | |
| | |LSN: 2078 | |
|---------------------------|-------------|---------------|----------------|然后更改内存中的数据页(我只更改IsDirty以简化)
/--------------- IN MEMORY --------------\/------------ IN DISK -----------\
|--------------------------------------------------------------------------|
|Buffer Pool | Log Buffer | Data File |Transaction Log |
|---------------------------|-------------|---------------|----------------|
|Page 1:24312 |LSN:7214 |Page: 1:24312 |LSN:7213 |
|IsDirty: TRUE |Op:Update |LSN: 4845 | |
|LSN: 4845 |Page:1:24312 |Page: 1:24313 | |
|... |OldLsn:4845 |LSN: 2078 | |
|Page 1:26912 |Row:2 |... | |
|isDirty:False |Tran:T1 |Page: 1:26911 | |
|LSN:1053 |PrevLSN:7141 |LSN: 2078 | |
| | |Page: 1:26912 | |
| | |LSN: 2078 | |
|---------------------------|-------------|---------------|----------------|这种情况一直持续到日志缓冲区已满或事务已提交。提交在日志缓冲区中生成另一个条目,OP在其中提交,并将整个缓冲区刷新到磁盘。
/--------------- IN MEMORY --------------\/------------ IN DISK -----------\
|--------------------------------------------------------------------------|
|Buffer Pool | Log Buffer | Data File |Transaction Log |
|---------------------------|-------------|---------------|----------------|
|Page 1:24312 | |Page: 1:24312 |LSN:7213 |
|IsDirty: TRUE | |LSN: 4845 | |
|LSN: 4845 | |Page: 1:24313 |LSN:7214 |
|... | |LSN: 2078 |<ALL PROPERTIES>|
|Page 1:26912 | |... | |
|isDirty:False | |Page: 1:26911 |LSN:7215 |
|LSN:1053 | |LSN: 2078 |Op:Commit |
| | |Page: 1:26912 | |
| | |LSN: 2078 |LSN:7216 |
| | | |Op:Checkpoint |
|---------------------------|-------------|---------------|----------------|此时,Server将回答客户端事务成功。值得指出的是,内存中的脏页尚未发送到磁盘。此时,如果发生了什么事情,Server将能够恢复对此点的所有更改。
这种技术称为先写日志,有关更多信息,请参见:
白羊座以外的历史重演
http://www.vldb.org/conf/1999/P1.pdf
在某个时刻,检查点进程将创建一个检查点操作,将缓冲区池中的所有脏页刷新到磁盘。如上面的例子所示,检查点操作也会出现在事务日志中。
考虑到这一点,我们可以看到Server如何对待事务日志。
虚拟日志文件
磁盘上的事务日志在虚拟日志文件(VLF)中被细分.你可以看到它在运行:
DBCC LOGINFO重要的是虚拟日志文件( Virtual,VLF)可以分为活动的或非活动的。
Server仅在事务日志的恢复模型中使用事务日志的活动部分。所以简单和完全的区别是当一个VLF变成非活动的时候。SQL Server禁用VLF,因为事务日志是一个环绕文件,意思是,“当逻辑日志文件的结尾到达物理文件的末尾时,日志将环绕它”。例如:
/------ACTIVE-----\/----------------INACTIVE----------------\/--------ACTIVE---\
|------------------------------------------------------------------------------|
| | | | | | | | |
| VLF1 | VLF2 | VLF3 | VLF4 | VLF5 | VLF6 | VLF7 | VLF8 |
| | | | | | | | |
|------------------------------------------------------------------------------|因此,如果由于某种原因没有VLF成为非活动,事务日志将需要无限增长。
简单恢复中的
回到这个例子。在检查点之后,并且所有内容都刷新到磁盘后,SQL Server在简单恢复中只会保持激活的VLF,即:
1-包含最古老的活动事务的最古老的LSN;或
2-最后一个检查站。
例如:
在检查站之前
/------INACTIVE---\/----------------ACTIVE-------\/---------INACTIVE-----------\
|------------------------------------------------------------------------------|
| | | | | | | | |
| VLF1 | VLF2 | VLF3 | VLF4 | VLF5 | VLF6 | VLF7 | VLF8 |
| | | | | | | | |
|------------------------------------------------------------------------------|
^ ^ ^ ^ ^
| | | | |> End of logical LOG file
| | | |> Current LSN
| | |> Minumin LSN (Oldest Active Transaction)
| |> Last Checkpoint
|> Start of Logical LOG file在检查站之后
/------INACTIVE---------------\/----ACTIVE-------\/---------INACTIVE-----------\
|------------------------------------------------------------------------------|
| | | | | | | | |
| VLF1 | VLF2 | VLF3 | VLF4 | VLF5 | VLF6 | VLF7 | VLF8 |
| | | | | | | | |
|------------------------------------------------------------------------------|
^ ^ ^ ^
| | | |> End of logical LOG file
| | |> Current LSN (Checkpoint Occurs)
| |> Minumin LSN (Oldest Active Transaction)
|> Start of Logical LOG fileServer已禁用包含上一个检查点的VLF3,因为:
新的检查点迫使内存中的所有脏页都进入磁盘。因此,不需要重做存储在VLF3中的任何更改,因为最古老的活动事务在VLF4中;
但是,由于这一点,我们仍然需要VLF4来支持所有活动事务的回滚。
全恢复期
在完全恢复过程中也会发生相同的过程,但现在将保持活动状态的最后一个VLF将是最古老的:
1-上一次日志备份的LSN;
2-最古老的活动事务的LSN;或
读取事务日志记录的进程的LSN。
例如
/------INACTIVE---------------\/----ACTIVE-------\/---------INACTIVE-----------\
|------------------------------------------------------------------------------|
| | | | | | | | |
| VLF1 | VLF2 | VLF3 | VLF4 | VLF5 | VLF6 | VLF7 | VLF8 |
| | | | | | | | |
|------------------------------------------------------------------------------|
^ ^ ^ ^ ^
| | | | |> End of logical LOG file
| | | |> Current LSN (Checkpoint Occurs)
| | |> Minumin LSN (Oldest Active Transaction)
| |> Replication log Reader
|> Start of Logical LOG file在本例中,复制日志阅读器迫使VLF4保持活动状态。
或
/------INACTIVE---\/----------------ACTIVE-------\/---------INACTIVE-----------\
|------------------------------------------------------------------------------|
| | | | | | | | |
| VLF1 | VLF2 | VLF3 | VLF4 | VLF5 | VLF6 | VLF7 | VLF8 |
| | | | | | | | |
|------------------------------------------------------------------------------|
^ ^ ^ ^ ^ ^
| | | | | |> End of logical LOG file
| | | | |> Current LSN (Checkpoint Occurs)
| | | |> Minumin LSN (Oldest Active Transaction)
| | |> Replication log Reader
| |> Last Transaction Log Backup
|> Start of logical LOG file在本例中,“最后一次事务日志备份”迫使VLF3保持活动状态。
我希望这些有助于更好地理解Server的工作方式。
发布于 2016-07-26 13:07:22
查看更多关于恢复模式的详细信息,这里。
DML查询将始终写入日志,以便能够回滚。基本上,一旦提交了事务,简单恢复就不会保留日志,但是它们在执行时仍然是写的。
https://stackoverflow.com/questions/38590066
复制相似问题