MySQL學習筆記(二)一條SQL更新語句

2021-09-22 14:12:37 字數 2636 閱讀 5743

從乙個表的一條更新語句說起,下面是這個表的建立語句,這個表有乙個主鍵id和乙個整型欄位c

mysql> create table t(id int primary key, c int);

假如將id=2這一行的值加1

執行語句要先通過聯結器連線資料庫。在乙個表上更新的時候,跟這個表有關的查詢快取會失效。

接下來分析器會通過詞法和語法解析知道這是一條更新語句。優化器決定要使用id這個索引。然後,執行器負責執行,找到這一行然後更新。

與查詢不同,更新和涉及到兩個重要的日誌模組:redo log(重做日誌)和binlog(歸檔日誌)

wal技術(write-ahead logging):先寫日誌,再寫磁碟。因為如果每次都直接寫磁碟的話會效率很低很慢,所以等不忙的時候再寫入磁碟。

具體,就是當有一條記錄需要更新的時候,innodb引擎會先把記錄寫到redo log裡面,並更新記憶體。這個時候更新算完成。然後引擎會在適當的時候,再將這個操作記錄更新到磁碟裡,這時往往是系統比較空閒的時候。

但是redo log是固定的大小。有時候,假如記憶體太滿,就必須先將一部分記憶體更新到磁碟,再將這部分擦掉,然後在記憶體中寫入新的操作

假如說可以配置為一組4個檔案,每個大小1g,那麼總共可以記錄4gb的操作。write pos是當前記錄的位置,一邊寫一邊後移,寫到第3號檔案末尾就回到了0號檔案開頭。checkpoint是當前要擦除的位置,也是往後推移並迴圈。

write pos和checkpoint之間是還空著的部分,可以記錄新的操作。如果write pos追上checkpoint,這時代表redo log已滿,得先擦掉一些記錄,把checkpoint推進一下。

redo log可以使資料庫即使發生異常重啟,之前提交的記錄也不會丟失,這稱為crash-safe。

redo log是innodb引擎特有的日誌,而server層自己的日誌稱為binlog,所有引擎都可使用。

redo log是物理日誌,記錄「在某資料頁做了什麼修改」。binlog是邏輯日誌,記錄這個語句的原始邏輯,「給id=2這行的c欄位加1」

redo log是迴圈寫,空間固定會用完。binlog是追加寫入,指檔案寫到一定大小會切換到下乙個,並不會覆蓋。

接下來是更新流程:

1.執行器先找到引擎取id=2這一行。id是主鍵,引擎通過樹搜尋找到這一行。如果這一行的資料頁本來就在記憶體,就直接返回給執行器;否則需要先從磁碟讀入記憶體,再返回。

2.執行器給這個值加1,再呼叫引擎介面寫入這行新資料。

3.引擎將這行資料更新到記憶體,同時將這個更新操作記錄到redo log。此時redo log會處於prepare狀態,告知執行器執行完成,隨時可提交。

4.執行器生成這個操作的binlog,並把binlog寫入磁碟。

5.執行器呼叫引擎提交的事務介面,引擎把剛剛寫入的redo log改為commit狀態,更新完成。

redo log的寫入在最後被binlog拆為兩個步驟:prepare和commit,這就是兩階段提交。

怎麼讓資料庫恢復到半個月內任意一秒的狀態?

這意味著備份系統中儲存著最近半個月所有的binlog,同時系統會做定期的整庫備份。可以一天一備,也可一周一備。

一天一備對比一周一備的好處是「最長恢復時間」更短。最壞的情況是需要應用一天的binlog。比如每天0點做全量備份,而要恢復出乙個到昨晚23點的備份。一周一備最壞的情況就是用一周的binlog。

當然更頻繁的全量備份需要消耗更多儲存空間。需要根據業務重要性來評估。

比如發現某天下午兩點發現中午十二點有一次誤刪表,需要找回資料,那可以:

首先找到最近一次全庫備份,如果運氣好就是昨晚乙個備份,從這個備份恢復到臨時庫。

然後從備份的時間點開始,將備份的binlog依次取出,重放到中午誤刪那個時刻。

然後就可以將表資料從臨時庫取出來,按需要恢復到線上庫。

假如不是兩階段:

1.先寫redo log後寫binlog。假設在redo log寫完還沒寫binlog,也就是redo log寫完即使崩潰,仍然能夠把資料庫恢復回來,這一行的c就是加完後的1。但是binlog沒有寫完,存起來的binlog就沒有這條語句。如果後來用binlog恢復臨時庫,由於這句缺失,導致臨時庫恢復的這行就是0,與原庫不同。

2.先寫binlog後寫redo log。假如binlog寫完後crash,redo log還沒寫,崩潰後恢復這行c還是0。但是binlog裡面已經記錄了把c從0改為1這個日誌,所以之後用binlog來恢復就多出乙個事務,恢復的c就是1,與原庫不同。

可以看到如果不是兩階段提交,那麼資料庫的狀態可能就和用它的日誌恢復出來的不一致。

兩階段提交就是讓這兩個狀態保持邏輯上的一致。

mysql 插入更新一條sql 搞定

插入資料時,我們經常會遇到這樣的情況 1 首先判斷資料是否存在 2 如果不存在,則插入 3 如果存在,則更新。在sql server中可以這樣處理 if not exists select 1 from t where id 1 insert into t id,update time values...

MYSQL 一條sql的執行過程

1 sql介面,負責接收處理收到的sql語句。2 查詢解析器,負責對sql語句進行解析,讓mysql能看懂sql語句,按照sql語法解析出這條sql要幹啥。3 查詢優化器,選擇最優的查詢路徑,指定執行計畫 全表掃瞄還是走索引 4 呼叫儲存引擎介面真正開始執行sql語句。儲存引擎就是用來執行sql的,...

MySql 一條查詢SQL語句的執行

這個的快取不是指redis,或者mybatis的快取我們常見的快取,其實mysql自帶了快取模組,但是我們幾乎從來沒有用過他,甚至在mysql8.0直接就給去掉了,所以一定有他的侷限性,大家可以查閱一下,但是確實是存在的。如果開啟的話,所以乙個查詢sql先會查詢快取 我們沒有使用快取的話,就會跳過快...