MySQL學習筆記事務篇:redo日誌

目錄

預寫式日誌

bin log

binlog和事務日誌的先後順序及group commit

redo log

不適用零拷貝技術的原因

日誌塊(log block)

redo log的格式

日誌刷盤的規則

數據頁刷盤的規則及checkpoint

LSN詳細分析

innodb的恢復行爲

和redo log有關的幾個變量

redo log和二進制日誌的區別


預寫式日誌

innodb通過force log at commit機制實現事務的持久性,即在事務提交的時候,必須先將該事務的所有事務日誌寫入到磁盤上的redo log file和undo log file中進行持久化。這種方式稱爲預寫式日誌。

大概過程:

     1.在緩衝區的事務日誌中寫入”Begin Tran”記錄

     2.在緩衝區的事務日誌頁寫入要修改的信息

     3.在緩衝區將要修改的數據寫入數據頁

     4.在緩衝區的日誌中寫入”Commit”記錄

     5.將緩衝區的日誌寫入磁盤日誌文件

     6.將緩衝區內的數據頁寫入到磁盤

bin log

二進制日誌是在存儲引擎的上層(屬於MySQL結構層面產生的,不管是什麼存儲引擎,對數據庫進行了修改都會產生二進制日誌。類似於redis AOF備份的一種方式,就是將除了SELECT和SHOW,其餘修改的命令全部記錄下來。並且二進制日誌先於redo log被記錄

二進制日誌記錄操作的方法是邏輯性的語句。即便它是基於行格式的記錄方式,其本質也還是邏輯的SQL設置,如該行記錄的每列的值是多少。

二進制日誌只在每次事務提交的時候一次性寫入緩存中的日誌"文件",所以二進制日誌中的記錄方式和提交順序有關,且一次提交對應一次記錄。

binlog和事務日誌的先後順序及group commit

如果事務不是隻讀事務,即涉及到了數據的修改,默認情況下會在commit的時候調用fsync()將日誌刷到磁盤,保證事務的持久性。

但是一次刷一個事務的日誌性能較低,特別是事務集中在某一時刻時事務量非常大的時候。innodb提供了group commit功能,可以將多個事務的事務日誌通過一次fsync()刷到磁盤中。

因爲事務在提交的時候不僅會記錄事務日誌,還會記錄二進制日誌,但是它們誰先記錄呢?二進制日誌是MySQL的上層日誌,先於存儲引擎的事務日誌被寫入。

在MySQL5.6以前,當事務提交(即發出commit指令)後,MySQL接收到該信號進入commit prepare階段;進入prepare階段後,立即寫內存中的二進制日誌,寫完內存中的二進制日誌後就相當於確定了commit操作;然後開始寫內存中的事務日誌;最後將二進制日誌和事務日誌刷盤,它們如何刷盤,分別由變量 sync_binlog 和 innodb_flush_log_at_trx_commit 控制。

但因爲要保證二進制日誌和事務日誌的一致性,在提交後的prepare階段會啓用一個prepare_commit_mutex鎖來保證它們的順序性和一致性。但這樣會導致開啓二進制日誌後group commmit失效,特別是在主從複製結構中,幾乎都會開啓二進制日誌。

在MySQL5.6中進行了改進。提交事務時,在存儲引擎層的上一層結構中會將事務按序放入一個隊列,隊列中的第一個事務稱爲leader,其他事務稱爲follower,leader控制着follower的行爲。雖然順序還是一樣先刷二進制,再刷事務日誌,但是機制完全改變了:刪除了原來的prepare_commit_mutex行爲,也能保證即使開啓了二進制日誌,group commit也是有效的。

MySQL5.6中分爲3個步驟:flush階段、sync階段、commit階段。

  • flush階段:向內存中寫入每個事務的二進制日誌。
  • sync階段:將內存中的二進制日誌刷盤。若隊列中有多個事務,那麼僅一次fsync操作就完成了二進制日誌的刷盤操作。這在MySQL5.6中稱爲BLGC(binary log group commit)。
  • commit階段:leader根據順序調用存儲引擎層事務的提交,由於innodb本就支持group commit,所以解決了因爲鎖 prepare_commit_mutex 而導致的group commit失效問題。

在flush階段寫入二進制日誌到內存中,但是不是寫完就進入sync階段的,而是要等待一定的時間,多積累幾個事務的binlog一起進入sync階段,等待時間由變量 binlog_max_flush_queue_time 決定,默認值爲0表示不等待直接進入sync,設置該變量爲一個大於0的值的好處是group中的事務多了,性能會好一些,但是這樣會導致事務的響應時間變慢,所以建議不要修改該變量的值,除非事務量非常多並且不斷的在寫入和更新。

進入到sync階段,會將binlog從內存中刷入到磁盤,刷入的數量和單獨的二進制日誌刷盤一樣,由變量 sync_binlog 控制。

當有一組事務在進行commit階段時,其他新事務可以進行flush階段,它們本就不會相互阻塞,所以group commit會不斷生效。當然,group commit的性能和隊列中的事務數量有關,如果每次隊列中只有1個事務,那麼group commit和單獨的commit沒什麼區別,當隊列中事務越來越多時,即提交事務越多越快時,group commit的效果越明顯。

redo log

redo log通常是物理日誌,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交後的物理數據頁(恢復數據頁,且只能恢復到最後一次提交的位置)。

redo log包括兩部分:一是內存中的日誌緩衝(redo log buffer),該部分日誌是易失性的;二是磁盤上的重做日誌文件(redo log file),該部分日誌是持久的。

爲了確保每次日誌都能寫入到事務日誌文件中,在每次將log buffer中的日誌寫入日誌文件的過程中都會調用一次操作系統的fsync操作(即fsync()系統調用)。因爲MariaDB/MySQL是工作在用戶空間的,MariaDB/MySQL的log buffer處於用戶空間的內存中。要寫入到磁盤上的log file中(redo:ib_logfileN文件,undo:share tablespace或.ibd文件),中間還要經過操作系統內核空間的os buffer,調用fsync()的作用就是將OS buffer中的日誌刷到磁盤上的log file中。

也就是說,從redo log buffer寫日誌到磁盤的redo log file中,過程如下:

不適用零拷貝技術的原因

之所以要經過一層os buffer,是因爲open日誌文件的時候,open沒有使用O_DIRECT標誌位,該標誌位意味着繞過操作系統層的os buffer,IO直寫到底層存儲設備。不使用該標誌位意味着將日誌進行緩衝,緩衝到了一定容量,或者顯式fsync()纔會將緩衝中的刷到存儲設備。使用該標誌位意味着每次都要發起系統調用。比如寫abcde,不使用o_direct將只發起一次系統調用,使用o_object將發起5次系統調用。

MySQL支持用戶自定義在commit時如何將log buffer中的日誌刷log file中。這種控制通過變量 innodb_flush_log_at_trx_commit 的值來決定。該變量有3種值:0、1、2,默認爲1。但注意,這個變量只是控制commit動作是否刷新log buffer到磁盤。

  • 當設置爲1的時候,事務每次提交都會將log buffer中的日誌寫入os buffer並調用fsync()刷到log file on disk中。這種方式即使系統崩潰也不會丟失任何數據,但是因爲每次提交都寫入磁盤,IO的性能較差。
  • 當設置爲0的時候,事務提交時不會將log buffer中日誌寫入到os buffer,而是每秒寫入os buffer並調用fsync()寫入到log file on disk中。也就是說設置爲0時是(大約)每秒刷新寫入到磁盤中的,當系統崩潰,會丟失1秒鐘的數據。
  • 當設置爲2的時候,每次提交都僅寫入到os buffer,然後是每秒調用fsync()將os buffer中的日誌寫入到log file on disk。

其實值爲2和0的時候,它們的差距並不太大,但2卻比0要安全的多。它們都是每秒從os buffer刷到磁盤,它們之間的時間差體現在log buffer刷到os buffer上。因爲將log buffer中的日誌刷新到os buffer只是內存數據的轉移,並沒有太大的開銷,所以每次提交和每秒刷入差距並不大。選擇刷日誌的時間會嚴重影響數據修改時的性能,特別是刷到磁盤的過程。

在主從複製結構中,要保證事務的持久性和一致性,需要對日誌相關變量設置爲如下:

  • 如果啓用了二進制日誌,則設置sync_binlog=1,即每提交一次事務同步寫到磁盤中。
  • 總是設置innodb_flush_log_at_trx_commit=1,即每提交一次事務都寫到磁盤中。

上述兩項變量的設置保證了:每次提交事務都寫入二進制日誌和事務日誌,並在提交時將它們刷新到磁盤中。

日誌塊(log block)

innodb存儲引擎中,redo log以塊爲單位進行存儲的,每個塊佔512字節,這稱爲redo log block。所以不管是log buffer中還是os buffer中以及redo log file on disk中,都是這樣以512字節的塊存儲的。

每個redo log block由3部分組成:日誌塊頭、日誌塊尾和日誌主體。其中日誌塊頭佔用12字節,日誌塊尾佔用8字節,所以每個redo log block的日誌主體部分只有512-12-8=492字節。

因爲redo log記錄的是數據頁的變化,當一個數據頁產生的變化需要使用超過492字節()的redo log來記錄,那麼就會使用多個redo log block來記錄該數據頁的變化。

日誌塊頭包含4部分:

  • log_block_hdr_no:(4字節)該日誌塊在redo log buffer中的位置ID。
  • log_block_hdr_data_len:(2字節)該log block中已記錄的log大小。寫滿該log block時爲0x200,表示512字節。
  • log_block_first_rec_group:(2字節)該log block中第一個log的開始偏移位置。
  • lock_block_checkpoint_no:(4字節)寫入檢查點信息的位置。

關於log block塊頭的第三部分 log_block_first_rec_group ,因爲有時候一個數據頁產生的日誌量超出了一個日誌塊,這是需要用多個日誌塊來記錄該頁的相關日誌。例如,某一數據頁產生了552字節的日誌量,那麼需要佔用兩個日誌塊,第一個日誌塊佔用492字節,第二個日誌塊需要佔用60個字節,那麼對於第二個日誌塊來說,它的第一個log的開始位置就是73字節(60+12)。如果該部分的值和 log_block_hdr_data_len 相等,則說明該log block中沒有新開始的日誌塊,即表示該日誌塊用來延續前一個日誌塊。

日誌尾只有一個部分: log_block_trl_no ,該值和塊頭的 log_block_hdr_no 相等。

上面所說的是一個日誌塊的內容,在redo log buffer或者redo log file on disk中,由很多log block組成。如下圖:

redo log的格式

因爲innodb存儲引擎存儲數據的單元是頁(和SQL Server中一樣),所以redo log也是基於頁的格式來記錄的。默認情況下,innodb的頁大小是16KB(由 innodb_page_size 變量控制),一個頁內可以存放非常多的log block(每個512字節),而log block中記錄的又是數據頁的變化。

其中log block中492字節的部分是log body,該log body的格式分爲4部分:

  • redo_log_type:佔用1個字節,表示redo log的日誌類型。
  • space:表示表空間的ID,採用壓縮的方式後,佔用的空間可能小於4字節。
  • page_no:表示頁的偏移量,同樣是壓縮過的。
  • redo_log_body表示每個重做日誌的數據部分,恢復時會調用相應的函數進行解析。例如insert語句和delete語句寫入redo log的內容是不一樣的。

如下圖,分別是insert和delete大致的記錄方式。

日誌刷盤的規則

og buffer中未刷到磁盤的日誌稱爲髒日誌(dirty log)。

在上面的說過,默認情況下事務每次提交的時候都會刷事務日誌到磁盤中,這是因爲變量 innodb_flush_log_at_trx_commit 的值爲1。但是innodb不僅僅只會在有commit動作後纔會刷日誌到磁盤,這只是innodb存儲引擎刷日誌的規則之一。

刷日誌到磁盤有以下幾種規則:

1.發出commit動作時。已經說明過,commit發出後是否刷日誌由變量 innodb_flush_log_at_trx_commit 控制。

2.每秒刷一次。這個刷日誌的頻率由變量 innodb_flush_log_at_timeout 值決定,默認是1秒。要注意,這個刷日誌頻率和commit動作無關。

3.當log buffer中已經使用的內存超過一半時。

4.當有checkpoint時,checkpoint在一定程度上代表了刷到磁盤時日誌所處的LSN位置。

數據頁刷盤的規則及checkpoint

內存中(buffer pool)未刷到磁盤的數據稱爲髒數據(dirty data)。由於數據和日誌都以頁的形式存在,所以髒頁表示髒數據和髒日誌。

上一節介紹了日誌是何時刷到磁盤的,不僅僅是日誌需要刷盤,髒數據頁也一樣需要刷盤。

在innodb中,數據刷盤的規則只有一個:checkpoint。但是觸發checkpoint的情況卻有幾種。不管怎樣,checkpoint觸發後,會將buffer中髒數據頁和髒日誌頁都刷到磁盤。

innodb存儲引擎中checkpoint分爲兩種:

  • sharp checkpoint:在重用redo log文件(例如切換日誌文件)的時候,將所有已記錄到redo log中對應的髒數據刷到磁盤。
  • fuzzy checkpoint:一次只刷一小部分的日誌到磁盤,而非將所有髒日誌刷盤。有以下幾種情況會觸發該檢查點:
    • master thread checkpoint:由master線程控制,每秒或每10秒刷入一定比例的髒頁到磁盤。
    • flush_lru_list checkpoint:從MySQL5.6開始可通過 innodb_page_cleaners 變量指定專門負責髒頁刷盤的page cleaner線程的個數,該線程的目的是爲了保證lru列表有可用的空閒頁。
    • async/sync flush checkpoint:同步刷盤還是異步刷盤。例如還有非常多的髒頁沒刷到磁盤(非常多是多少,有比例控制),這時候會選擇同步刷到磁盤,但這很少出現;如果髒頁不是很多,可以選擇異步刷到磁盤,如果髒頁很少,可以暫時不刷髒頁到磁盤
    • dirty page too much checkpoint:髒頁太多時強制觸發檢查點,目的是爲了保證緩存有足夠的空閒空間。too much的比例由變量 innodb_max_dirty_pages_pct 控制,MySQL 5.6默認的值爲75,即當髒頁佔緩衝池的百分之75後,就強制刷一部分髒頁到磁盤。

由於刷髒頁需要一定的時間來完成,所以記錄檢查點的位置是在每次刷盤結束之後纔在redo log中標記的。

MySQL停止時是否將髒數據和髒日誌刷入磁盤,由變量innodb_fast_shutdown={ 0|1|2 }控制,默認值爲1,即停止時只做一部分purge,忽略大多數flush操作(但至少會刷日誌),在下次啓動的時候再flush剩餘的內容,實現fast shutdown。

LSN詳細分析

LSN稱爲日誌的邏輯序列號(log sequence number),在innodb存儲引擎中,lsn佔用8個字節。LSN的值會隨着日誌的寫入而逐漸增大。

根據LSN,可以獲取到幾個有用的信息:

1.數據頁的版本信息。

2.寫入的日誌總量,通過LSN開始號碼和結束號碼可以計算出寫入的日誌量。

3.可知道檢查點的位置。

實際上還可以獲得很多隱式的信息。

LSN不僅存在於redo log中,還存在於數據頁中,在每個數據頁的頭部,有一個fil_page_lsn記錄了當前頁最終的LSN值是多少。通過數據頁中的LSN值和redo log中的LSN值比較,如果頁中的LSN值小於redo log中LSN值,則表示數據丟失了一部分,這時候可以通過redo log的記錄來恢復到redo log中記錄的LSN值時的狀態。

innodb從執行修改語句開始:

(1).首先修改內存中的數據頁,並在數據頁中記錄LSN,暫且稱之爲data_in_buffer_lsn;

(2).並且在修改數據頁的同時(幾乎是同時)向redo log in buffer中寫入redo log,並記錄下對應的LSN,暫且稱之爲redo_log_in_buffer_lsn;

(3).寫完buffer中的日誌後,當觸發了日誌刷盤的幾種規則時,會向redo log file on disk刷入重做日誌,並在該文件中記下對應的LSN,暫且稱之爲redo_log_on_disk_lsn;

(4).數據頁不可能永遠只停留在內存中,在某些情況下,會觸發checkpoint來將內存中的髒頁(數據髒頁和日誌髒頁)刷到磁盤,所以會在本次checkpoint髒頁刷盤結束時,在redo log中記錄checkpoint的LSN位置,暫且稱之爲checkpoint_lsn。

(5).要記錄checkpoint所在位置很快,只需簡單的設置一個標誌即可,但是刷數據頁並不一定很快,例如這一次checkpoint要刷入的數據頁非常多。也就是說要刷入所有的數據頁需要一定的時間來完成,中途刷入的每個數據頁都會記下當前頁所在的LSN,暫且稱之爲data_page_on_disk_lsn。

上圖中,從上到下的橫線分別代表:時間軸、buffer中數據頁中記錄的LSN(data_in_buffer_lsn)、磁盤中數據頁中記錄的LSN(data_page_on_disk_lsn)、buffer中重做日誌記錄的LSN(redo_log_in_buffer_lsn)、磁盤中重做日誌文件中記錄的LSN(redo_log_on_disk_lsn)以及檢查點記錄的LSN(checkpoint_lsn)。

假設在最初時(12:0:00)所有的日誌頁和數據頁都完成了刷盤,也記錄好了檢查點的LSN,這時它們的LSN都是完全一致的。

假設此時開啓了一個事務,並立刻執行了一個update操作,執行完成後,buffer中的數據頁和redo log都記錄好了更新後的LSN值,假設爲110。這時候如果執行 show engine innodb status 查看各LSN的值,即圖中①處的位置狀態,結果會是:

log sequence number(110) > log flushed up to(100) = pages flushed up to = last checkpoint at

之後又執行了一個delete語句,LSN增長到150。等到12:00:01時,觸發redo log刷盤的規則(其中有一個規則是 innodb_flush_log_at_timeout 控制的默認日誌刷盤頻率爲1秒),這時redo log file on disk中的LSN會更新到和redo log in buffer的LSN一樣,所以都等於150,這時 show engine innodb status ,即圖中②的位置,結果將會是:

log sequence number(150) = log flushed up to > pages flushed up to(100) = last checkpoint at

再之後,執行了一個update語句,緩存中的LSN將增長到300,即圖中③的位置。

假設隨後檢查點出現,即圖中④的位置,正如前面所說,檢查點會觸發數據頁和日誌頁刷盤,但需要一定的時間來完成,所以在數據頁刷盤還未完成時,檢查點的LSN還是上一次檢查點的LSN,但此時磁盤上數據頁和日誌頁的LSN已經增長了,即:

log sequence number > log flushed up to 和 pages flushed up to > last checkpoint at

但是log flushed up to和pages flushed up to的大小無法確定,因爲日誌刷盤可能快於數據刷盤,也可能等於,還可能是慢於。但是checkpoint機制有保護數據刷盤速度是慢於日誌刷盤的:當數據刷盤速度超過日誌刷盤時,將會暫時停止數據刷盤,等待日誌刷盤進度超過數據刷盤。

等到數據頁和日誌頁刷盤完畢,即到了位置⑤的時候,所有的LSN都等於300。

隨着時間的推移到了12:00:02,即圖中位置⑥,又觸發了日誌刷盤的規則,但此時buffer中的日誌LSN和磁盤中的日誌LSN是一致的,所以不執行日誌刷盤,即此時 show engine innodb status 時各種lsn都相等。

隨後執行了一個insert語句,假設buffer中的LSN增長到了800,即圖中位置⑦。此時各種LSN的大小和位置①時一樣。

隨後執行了提交動作,即位置⑧。默認情況下,提交動作會觸發日誌刷盤,但不會觸發數據刷盤,所以 show engine innodb status 的結果是:

log sequence number = log flushed up to > pages flushed up to = last checkpoint at

最後隨着時間的推移,檢查點再次出現,即圖中位置⑨。但是這次檢查點不會觸發日誌刷盤,因爲日誌的LSN在檢查點出現之前已經同步了。假設這次數據刷盤速度極快,快到一瞬間內完成而無法捕捉到狀態的變化,這時 show engine innodb status 的結果將是各種LSN相等。

innodb的恢復行爲

在啓動innodb的時候,不管上次是正常關閉還是異常關閉,總是會進行恢復操作。

因爲redo log記錄的是數據頁的物理變化,因此恢復的時候速度比邏輯日誌(如二進制日誌)要快很多。而且,innodb自身也做了一定程度的優化,讓恢復速度變得更快。

重啓innodb時,checkpoint表示已經完整刷到磁盤上data page上的LSN,因此恢復時僅需要恢復從checkpoint開始的日誌部分。例如,當數據庫在上一次checkpoint的LSN爲10000時宕機,且事務是已經提交過的狀態。啓動數據庫時會檢查磁盤中數據頁的LSN,如果數據頁的LSN小於日誌中的LSN,則會從檢查點開始恢復。

還有一種情況,在宕機前正處於checkpoint的刷盤過程,且數據頁的刷盤進度超過了日誌頁的刷盤進度。這時候一宕機,數據頁中記錄的LSN就會大於日誌頁中的LSN,在重啓的恢復過程中會檢查到這一情況,這時超出日誌進度的部分將不會重做,因爲這本身就表示已經做過的事情,無需再重做。

另外,事務日誌具有冪等性,所以多次操作得到同一結果的行爲在日誌中只記錄一次。而二進制日誌不具有冪等性,多次操作會全部記錄下來,在恢復的時候會多次執行二進制日誌中的記錄,速度就慢得多。例如,某記錄中id初始值爲2,通過update將值設置爲了3,後來又設置成了2,在事務日誌中記錄的將是無變化的頁,根本無需恢復;而二進制會記錄下兩次update操作,恢復時也將執行這兩次update操作,速度比事務日誌恢復更慢。

和redo log有關的幾個變量

  • innodb_flush_log_at_trx_commit={0|1|2} # 指定何時將事務日誌刷到磁盤,默認爲1。
    • 0表示每秒將"log buffer"同步到"os buffer"且從"os buffer"刷到磁盤日誌文件中。
    • 1表示每事務提交都將"log buffer"同步到"os buffer"且從"os buffer"刷到磁盤日誌文件中。
    • 2表示每事務提交都將"log buffer"同步到"os buffer"但每秒才從"os buffer"刷到磁盤日誌文件中。
  • innodb_log_buffer_size:# log buffer的大小,默認8M
  • innodb_log_file_size:#事務日誌的大小,默認5M
  • innodb_log_files_group =2:# 事務日誌組中的事務日誌文件個數,默認2個
  • innodb_log_group_home_dir =./:# 事務日誌組路徑,當前目錄表示數據目錄
  • innodb_mirrored_log_groups =1:# 指定事務日誌組的鏡像組個數,但鏡像功能好像是強制關閉的,所以只有一個log group。在MySQL5.7中該變量已經移除。

redo log和二進制日誌的區別

redo log不是二進制日誌。雖然二進制日誌中也記錄了innodb表的很多操作,也能實現重做的功能,但是它們之間有很大區別。

  1. 二進制日誌是在存儲引擎的上層產生的,不管是什麼存儲引擎,對數據庫進行了修改都會產生二進制日誌。而redo log是innodb層產生的,只記錄該存儲引擎中表的修改。並且二進制日誌先於redo log被記錄。具體的見後文group commit小結。
  2. 二進制日誌記錄操作的方法是邏輯性的語句。即便它是基於行格式的記錄方式,其本質也還是邏輯的SQL設置,如該行記錄的每列的值是多少。而redo log是在物理格式上的日誌,它記錄的是數據庫中每個頁的修改。
  3. 二進制日誌只在每次事務提交的時候一次性寫入緩存中的日誌"文件"。而redo log在數據準備修改前寫入緩存中的redo log中,然後纔對緩存中的數據執行修改操作;而且保證在發出事務提交指令時,先向緩存中的redo log寫入日誌,寫入完成後才執行提交動作。
  4. 因爲二進制日誌只在提交的時候一次性寫入,所以二進制日誌中的記錄方式和提交順序有關,且一次提交對應一次記錄。而redo log中是記錄的物理頁的修改,redo log文件中同一個事務可能多次記錄,最後一個提交的事務記錄會覆蓋所有未提交的事務記錄。例如事務T1,可能在redo log中記錄了 T1-1,T1-2,T1-3,T1* 共4個操作,其中 T1* 表示最後提交時的日誌記錄,所以對應的數據頁最終狀態是 T1* 對應的操作結果。而且redo log是併發寫入的,不同事務之間的不同版本的記錄會穿插寫入到redo log文件中,例如可能redo log的記錄方式如下: T1-1,T1-2,T2-1,T2-2,T2*,T1-3,T1* 。
  5. 事務日誌記錄的是物理頁的情況,它具有冪等性,因此記錄日誌的方式極其簡練。冪等性的意思是多次操作前後狀態是一樣的,例如新插入一行後又刪除該行,前後狀態沒有變化。而二進制日誌記錄的是所有影響數據的操作,記錄的內容較多。例如插入一行記錄一次,刪除該行又記錄一次。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章