2016-07-26 30 views
2

我想了解爲什麼下面的代碼寫入日誌文件。我是一名初學者,並且已經讀過,當數據庫處於簡單恢復模式時,不會寫入日誌。但下面的代碼是寫在全部和簡單恢復模式。在這種情況下,日誌文件是用簡單的恢復模式寫入的?日誌文件正在增長與簡單恢復模式

代碼:

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 

回答

2

首先,您的理解是,當數據庫處於簡單恢復模式時,沒有任何內容寫入日誌文件,是錯誤

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 

在你的榜樣,後交易已經開始,它結束之前(回滾/提交)有很多活動正在進行時,SQL Server需要登錄如果您決定像以前那樣回滾事務,那麼此活動就是如此,因此越來越多的日誌將被寫入日誌文件直到事務完成(Committed或Rollback)。

在這個特定的例子中,sql server必須保存100000個插入語句的日誌,以防萬一出現錯誤。


另一種略有不同的版本,您的查詢可能是......

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 
在此略有不同的版本相同的T-SQL命令的

現在有少了很多活動交易之後怎麼回事已經開始,並且在它完成之前,因此sql服務器必須記錄非常少的數據,並且如果有的話,事務文件將增長得非常少。

在此示例中,sql服務器必須一次只記錄一個insert語句,因爲它在該點之後被提交或回滾。

+0

正如@Bee_Riii所提到的,一旦事務被提交,簡單恢復將不會保留日誌。怎麼運行的?在我的例子中,如果我用COMMIT替換ROLLBACK,日誌仍然存在。 – p2k

+1

是什麼讓你認爲日誌仍然存在?由於日誌文件的大小?如果文件的大小已經增大並不意味着它有內部日誌,這意味着文件不夠大,無法寫入sql server必須寫入的所有日誌,因此文件已經增長。磁盤上的日誌文件大小和該文件中的日誌是兩回事。 –

+0

明白了,當我試圖收縮日誌文件時,它說93%的可用空間可用。這意味着它不是日誌數據而是它的文件大小。這清除了我的懷疑。謝謝 – p2k

0

退房更詳細的恢復模式here.

DML查詢將永遠寫入日誌,以便能夠回滾。在基本術語中,一旦事務被提交,簡單恢復將不會保留日誌,但它們在執行時仍會寫入。

2

我把所有的信息從這裏臨SQL服務器內部2014
https://www.amazon.com/Pro-Server-Internals-Dmitri-Korotkevitch/dp/1430259620

TL; DR;

恢復模式SIMPLE和FULL不同於SQL Server如何使虛擬日誌文件(VLF)失活。
總結:
1 - 「在SIMPLE恢復模型中,事務日誌的活動部分以VLF開頭,VLF包含最早的活動事務的最舊LSN或最後一個CHECKPOINT」;
2「 - 在完整或是批量日誌恢復模型,事務日誌的活動部分與VLF開始,其中包含最早的以下內容:
LSN最後一個日誌備份的
LSN最早的活動事務
的讀取事務日誌記錄」

LSN =日誌序列號=獨特,自動遞增ID

更詳細的解釋的過程中 LSN

假設這是SQL Server內存模型:
1 - 緩衝池是SQL Server存儲索引,行等內存的地方;
2 - 日誌緩衝區是事務日誌的一小部分(每個數據庫64KB)緩衝區;
3 - 數據文件是SQL Server將存儲索引,行等...在磁盤中的地方;
4 - 事務日誌是......磁盤中的事務日誌。

假設我們有一個數據庫處於以下狀態。

/--------------- 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 | 
|---------------------------|-------------|---------------|----------------| 

此時SQL Server將回答事務成功的客戶端。 值得指出的是內存中的髒頁還沒有被髮送到磁盤。 在這一點上,如果發生了什麼事SQL Server將能夠恢復到這個確切點的所有更改。
這種技術被稱爲預寫日誌記錄和詳細信息,請參閱:

重複歷史超越ARIES
http://www.vldb.org/conf/1999/P1.pdf

在某些時刻檢查點進程將創建刷新緩衝池中的所有髒頁的檢查點操作到磁盤。如上例所示,檢查點操作也出現在事務日誌中。

考慮到這一點,我們可以看到SQL Server如何處理事務日誌。

虛擬日誌文件

的事務日誌的磁盤上是細分在虛擬日誌文件(VLF)。您可以查看運行:

DBCC LOGINFO 

最重要的部分就是虛擬日誌文件(VLF)可以被歸類爲有效或無效。

SQL Server只在其恢復模型中使用事務日誌的活動部分。所以簡單和完全之間的區別是當一個VLF變成非活動時。 SQL Server停用VLF是因爲事務日誌是一個環繞文件,這意味着「當邏輯日誌文件的末尾達到物理文件的末尾時,日誌將環繞它」。例如:

/------ACTIVE-----\/----------------INACTIVE----------------\/--------ACTIVE---\ 
|------------------------------------------------------------------------------| 
|  |   |   |   |   |   |  |   | 
| VLF1 | VLF2 | VLF3 | VLF4 | VLF5 | VLF6 | VLF7 | VLF8 | 
|  |   |   |   |   |   |  |   | 
|------------------------------------------------------------------------------| 

因此,如果由於某種原因沒有VLF變爲無效,則事務日誌將需要無限增長。

處於簡單恢復

回過頭來看看這個例子。在檢查點之後,並且所有內容都刷新到磁盤,SIMPLE恢復中的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 file 

SQL服務器已經滅活包含最後一個檢查點的VLF3之後之前因爲:
1 - 新檢查點將內存中的所有髒頁面強制到磁盤上。因此,不需要重做存儲在VLF3中的任何更改,因爲最早的活動事務處於VLF4中;
2 - 但是,正因爲如此,我們仍然需要VLF4來支持所有活動事務的回滾。

處於完全恢復

同樣的過程發生在完全恢復,但現在最後的VLF將保持活躍將是最古老的來自:
1 - 最後的日誌備份的LSN;
2-OLDEST ACTIVE TRANSACTION的LSN;或
3 - 讀取事務日誌記錄的進程的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保持活躍。

我希望這些有助於更好地理解SQL Server的工作原理。