在數(shù)據(jù)庫里面会放,我們說的 update 操作其實包括了更新、插入和刪除兼都。如果大家有看過 MyBatis 的源碼旨涝,應該知道 Executor 里面也只有 doQuery()和 doUpdate()的方法,沒有 doDelete()和 doInsert()驾锰。
更新流程和查詢流程有什么不同呢??
基本流程也是一致的卸留,也就是說,它也要經過解析器稻据、優(yōu)化器的處理艾猜,最后交給執(zhí)行器。區(qū)別就在于拿到符合條件的數(shù)據(jù)之后的操作捻悯。
在講更新操作之前匆赃,我們先來理解 InnoDB 內存結構和磁盤結構
1.緩沖池 Buffer Pool
1)為啥會有Buffer Pool?
首先今缚,InnnoDB 的數(shù)據(jù)都是放在磁盤上的算柳,InnoDB 操作數(shù)據(jù)有一個最小的邏輯單位,叫做頁(索引頁和數(shù)據(jù)頁)姓言。我們對于數(shù)據(jù)的操作瞬项,不是每次都直接操作磁盤,因為磁盤的速度太慢了何荚。InnoDB 使用了一種緩沖池的技術囱淋,也就是把磁盤讀到的頁放到一塊內存區(qū)域里面。這個內存區(qū)域就叫 Buffer Pool餐塘。
2)Buffer Pool中具體的操作
11)下一次讀取相同的頁妥衣,先判斷是不是在緩沖池里面,如果是,就直接讀取税手,不用再次訪問磁盤蜂筹。? ? ? ? ? ? 22)修改數(shù)據(jù)的時候,先修改緩沖池里面的頁芦倒。內存的數(shù)據(jù)頁和磁盤數(shù)據(jù)不一致的時候艺挪,我們把它叫做臟頁。InnoDB 里面有專門的后臺線程把 Buffer Pool 的數(shù)據(jù)寫入到磁盤兵扬,每隔一段時間就一次性地把多個修改寫入磁盤麻裳,這個動作就叫做刷臟。
3)內存的緩沖池寫滿了怎么辦?
InnoDB 用 LRU算法來管理緩沖池(鏈表實現(xiàn)周霉,不是傳統(tǒng)的 LRU掂器,分成了 young 和 old),經過淘汰的數(shù)據(jù)就是熱點數(shù)據(jù)俱箱。
2.Change Buffer 寫緩沖
1)為啥會存在Change Buffer 国瓮?
當需要更新一個數(shù)據(jù)頁時,如果數(shù)據(jù)頁在 Buffer Pool 中存在狞谱,那么就直接更新好了乃摹。否則的話就需要從磁盤加載到內存,再對內存的數(shù)據(jù)頁進行操作跟衅。也就是說孵睬,如果沒有命中緩沖池,至少要產生一次磁盤 IO,這樣速度就會變慢伶跷,故存在用Change Buffer解決問題 掰读!
2)Change Buffer 具體的介紹?
如果這個數(shù)據(jù)頁不是唯一索引叭莫,不存在數(shù)據(jù)重復的情況蹈集,也就不需要從磁盤加載索引頁判斷數(shù)據(jù)是不是重復(唯一性檢查)。這種情況下可以先把修改記錄在內存的緩沖池中雇初,從而提升更新語句(Insert拢肆、Delete、Update)的執(zhí)行速度靖诗。這一塊區(qū)域就是 Change Buffer郭怪!
3)Change Buffer-----merge
mege定義:把 Change Buffer 記錄到數(shù)據(jù)頁的操作叫做 merge? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 什么時候發(fā)生 merge?1.在訪問這個數(shù)據(jù)頁的時候刊橘,2.通過后臺線程鄙才、3.數(shù)據(jù)庫 shut down、4.redo log 寫滿時觸發(fā)促绵。
4)啟發(fā):如果數(shù)據(jù)庫大部分索引都是非唯一索引攒庵,并且業(yè)務是寫多讀少据途,不會在寫數(shù)據(jù)后立刻讀取,就可以使用 Change Buffer(寫緩沖)叙甸。寫多讀少的業(yè)務,調大這個值位衩。SHOW VARIABLES LIKE 'innodb_change_buffer_max_size';
3.Adaptive Hash Index
索引應該是放在磁盤的裆蒸,為什么要專門把一種哈希的索引放到內存
4.(redo)Log Buffer
1)為啥會存在?redo log?
如果 Buffer Pool 里面的臟頁還沒有刷入磁盤時糖驴,數(shù)據(jù)庫宕機或者重啟僚祷,這些數(shù)據(jù)丟失。如果寫操作寫到一半贮缕,甚至可能會破壞數(shù)據(jù)文件導致數(shù)據(jù)庫不可用辙谜,為了避免這個問題,InnoDB 把所有對頁面的修改操作專門寫入一個日志文件感昼,并且在數(shù)據(jù)庫啟動時從這個文件進行恢復操作(實現(xiàn) crash-safe)——用它來實現(xiàn)事務的持久性装哆。這個文件就是磁盤的 redo log(叫做重做日志),對應于/var/lib/mysql/目錄下的ib_logfile0 和 ib_logfile1定嗓,每個 48M蜕琴。
2)WAL 技術: 這種日志和磁盤配合的整個過程, 它的關鍵點就是先寫日志,再寫磁盤宵溅。這種技術就叫做WAL 技術凌简。
3)同樣是寫磁盤,為什么不直接寫到 db file 里面去?為什么先寫日志再寫磁盤?
這里就涉及到順序io和隨機io恃逻,順序io的方式優(yōu)于隨機io雏搂。所以刷盤是隨機 I/O,而記錄日志是順序 I/O寇损,順序 I/O 效率更高凸郑。因此先把修改寫入日志,可以延遲刷盤時機润绵,進而提升系統(tǒng)吞吐线椰。
4)為啥會存在 Log Buffer
為了提高速度,redo log 也不是每一次都直接寫入磁盤尘盼,在 Buffer Pool 里面有一塊內存區(qū)域(Log Buffer)專門用來保存即將要寫入日志文件的數(shù)據(jù)憨愉,默認 16M,它一樣可以節(jié)省磁盤 IO卿捎。
5)Log Buffer 什么時候寫入 log file?
需要注意:redo log 的內容主要是用于崩潰恢復配紫。磁盤的數(shù)據(jù)文件,數(shù)據(jù)來自 bufferpool午阵。redo log 寫入磁盤躺孝,不是寫入數(shù)據(jù)文件享扔。那么,Log Buffer 什么時候寫入 log file?在我們寫入數(shù)據(jù)到磁盤的時候植袍,操作系統(tǒng)本身是有緩存的惧眠。flush 就是把操作系統(tǒng)緩沖區(qū)寫入到磁盤。log buffer 寫入磁盤的時機于个,由一個參數(shù)控制氛魁,默認是 1。https://dev.mysql.com/doc/refman/5.7/en/innodbparameters.html#sysvar_innodb_flush_log_at_trx_commit?
5.undo log
1)為啥會有undo log厅篓?
undo log( 撤 銷 日 志 或 回 滾 日 志 )記 錄 了 事 務 發(fā) 生 之 前 的 數(shù) 據(jù) 狀 態(tài)( 不 包 括 s e l e c t )秀存。如果修改數(shù)據(jù)時出現(xiàn)異常,可以用 undo log 來實現(xiàn)回滾操作(保持原子性)羽氮。在執(zhí)行 undo 的時候或链,僅僅是將數(shù)據(jù)從邏輯上恢復至事務之前的狀態(tài),而不是從物理頁面上操作實現(xiàn)的档押,屬于邏輯格式的日志澳盐。undolog里面寫的是更新操作的逆操作!---》在下面這圖中令宿,指的就是將4改為3洞就,將3改為2這樣的操作!
2)啥時候undolog中的記錄會被清除
在不需要的時候才刪除掀淘。也就是說旬蟋,系統(tǒng)會判斷,當沒有事務再需要用到這些回滾日志時革娄,回滾日志會被刪除倾贰!
3)事務日志
redo Log 和 undo Log 與事務密切相關,統(tǒng)稱為事務日志拦惋。
4)為啥不要使用長事務
長事務意味著系統(tǒng)里面會存在很老的事務視圖匆浙。由于這些事務隨時可能訪問數(shù)據(jù)庫里面的任何數(shù)據(jù),所以這個事務提交之前厕妖,數(shù)據(jù)庫里面它可能用到的回滾記錄都必須保留首尼,這就會導致大量占用存儲空間。
5)如何避免長事務呢
6.總結
1)一個更新操作的流程:update user set name = '周類' where id=1;
1言秸、事務開始软能,從內存或磁盤取到這條數(shù)據(jù),返回給 Server 的執(zhí)行器;? 2举畸、執(zhí)行器修改這一行數(shù)據(jù)的值為周磊; 3.記錄 name=周磊 到 undo log; 4.記錄 name=周磊 到 redo log; 5.調用存儲引擎接口查排,在內存(Buffer Pool)中修改 name=周磊; 6、 事務提交抄沮。
2) Binlog:這個日志存儲在server端跋核,binlog 以事件的形式記錄了所有的 DDL 和 DML 語句(因為它記錄的是操作而不是數(shù)據(jù)值岖瑰,屬于邏輯日志),可以用來做主從復制和數(shù)據(jù)恢復砂代。
3)一條更新語句具體執(zhí)行
1)先查詢到這條數(shù)據(jù)蹋订,如果有緩存,也會用到緩存刻伊。2)把 name 改成盆魚宴正勒,然后調用引擎的 API 接口误债,寫入這一行數(shù)據(jù)到內存穴亏,同時記錄 redo log挠乳。這時 redo log 進入 prepare 狀態(tài)蛾茉,然后告訴執(zhí)行器讼呢,執(zhí)行完成了,可以隨時提交谦炬。3)悦屏、執(zhí)行器收到通知后記錄 binlog,然后調用存儲引擎接口键思,設置 redo log 為 commit狀態(tài)础爬。4)、更新完成吼鳞。