首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >日志文件正在以简单的恢复模式增长。

日志文件正在以简单的恢复模式增长。
EN

Stack Overflow用户
提问于 2016-07-26 12:34:34
回答 3查看 7.2K关注 0票数 3

我试图了解为什么下面的代码要写入日志文件。我是个初学者,已经读过了,日志不是在数据库处于简单恢复模式时编写的。但是下面的代码是在完全恢复模式和简单恢复模式下编写的。在哪种情况下,日志文件是用简单的恢复模式编写的?

代码:

代码语言:javascript
复制
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
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-07-26 13:07:54

首先,您的理解是,在数据库处于简单恢复模式时,不会将任何内容写入日志文件,这是错误的

SQL Server在所有恢复模式下写入日志文件,唯一的区别是在简单恢复模式中,它会自动回收日志空间(如果可能的话),并记录维护事务的最少内容(如果您必须回滚事务)。

然而,在完全恢复模式下,我们必须进行事务日志备份,以便为SQL Server提供空间,以便用于进一步的日志记录。

现在回到您的例子:

代码语言:javascript
复制
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语句的日志,以防出问题。

另一个稍微不同的查询版本可能是..。

代码语言:javascript
复制
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语句的日志,因为在该语句之后提交或回滚。

票数 2
EN

Stack Overflow用户

发布于 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,事务日志在磁盘中。

假设我们有一个处于以下状态的数据库。

代码语言:javascript
复制
/--------------- 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      |                |
|---------------------------|-------------|---------------|----------------|

现在假设进行了更改,这是一个简单的更新。

第一步是在日志缓冲区中插入日志记录。

代码语言:javascript
复制
/--------------- 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以简化)

代码语言:javascript
复制
/--------------- 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在其中提交,并将整个缓冲区刷新到磁盘。

代码语言:javascript
复制
/--------------- 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)中被细分.你可以看到它在运行:

代码语言:javascript
复制
DBCC LOGINFO

重要的是虚拟日志文件( Virtual,VLF)可以分为活动的或非活动的。

Server仅在事务日志的恢复模型中使用事务日志的活动部分。所以简单和完全的区别是当一个VLF变成非活动的时候。SQL Server禁用VLF,因为事务日志是一个环绕文件,意思是,“当逻辑日志文件的结尾到达物理文件的末尾时,日志将环绕它”。例如:

代码语言:javascript
复制
/------ACTIVE-----\/----------------INACTIVE----------------\/--------ACTIVE---\
|------------------------------------------------------------------------------|
|        |         |          |         |         |         |        |         |
| VLF1   |   VLF2  |    VLF3  |  VLF4   |   VLF5  |   VLF6  |  VLF7  |  VLF8   |
|        |         |          |         |         |         |        |         |
|------------------------------------------------------------------------------|

因此,如果由于某种原因没有VLF成为非活动,事务日志将需要无限增长。

简单恢复中的

回到这个例子。在检查点之后,并且所有内容都刷新到磁盘后,SQL Server在简单恢复中只会保持激活的VLF,即:

1-包含最古老的活动事务的最古老的LSN;或

2-最后一个检查站。

例如:

在检查站之前

代码语言:javascript
复制
/------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

在检查站之后

代码语言:javascript
复制
/------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 file

Server已禁用包含上一个检查点的VLF3,因为:

新的检查点迫使内存中的所有脏页都进入磁盘。因此,不需要重做存储在VLF3中的任何更改,因为最古老的活动事务在VLF4中;

但是,由于这一点,我们仍然需要VLF4来支持所有活动事务的回滚。

全恢复期

在完全恢复过程中也会发生相同的过程,但现在将保持活动状态的最后一个VLF将是最古老的:

1-上一次日志备份的LSN;

2-最古老的活动事务的LSN;或

读取事务日志记录的进程的LSN。

例如

代码语言:javascript
复制
/------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保持活动状态。

代码语言:javascript
复制
/------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的工作方式。

票数 2
EN

Stack Overflow用户

发布于 2016-07-26 13:07:22

查看更多关于恢复模式的详细信息,这里。

DML查询将始终写入日志,以便能够回滚。基本上,一旦提交了事务,简单恢复就不会保留日志,但是它们在执行时仍然是写的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38590066

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档