MySQL實(shí)戰(zhàn)45講閱讀筆記-MySQL入門

系列
MySQL實(shí)戰(zhàn)45講閱讀筆記-MySQL入門
MySQL實(shí)戰(zhàn)45講閱讀筆記-日志
MySQL實(shí)戰(zhàn)45講閱讀筆記-鎖
MySQL實(shí)戰(zhàn)45講閱讀筆記-索引
MySQL實(shí)戰(zhàn)45講閱讀筆記-MVCC

MySQL的使用作為后端必須要掌握的一個(gè)技術(shù),還是需要了解下基本的原理,方便在我們工程實(shí)踐中對(duì)數(shù)據(jù)庫的運(yùn)用有更深入的了解,自己寫的SQL背后會(huì)發(fā)生什么事情恬叹,所以還是很有必要學(xué)習(xí)下基本的原理的;


當(dāng)然這幾篇是對(duì)MySQL官方文檔碟渺、網(wǎng)上博客和MySQL實(shí)戰(zhàn)45講的總結(jié)透典,沒有翻閱源碼惠勒,總結(jié)的知識(shí)點(diǎn)都是來自于別人的和別人的別人的所以可能相當(dāng)淺顯且錯(cuò)誤百出角钩,終究只是個(gè)閱讀筆記吝沫;

模塊

連接器

連接器負(fù)責(zé)跟客戶端建立連接、獲取權(quán)限递礼、維持和管理連接惨险。
在收到連接請(qǐng)求后,連接器會(huì)到權(quán)限表里面查出你擁有的權(quán)限脊髓。之后這個(gè)連接里面的權(quán)限判斷邏輯辫愉,都將依賴于此時(shí)讀到的權(quán)限。

可以通過show processlist或者show full processlist顯示當(dāng)前連接将硝,前者只顯示100條后者顯示全部恭朗,也可以到information_schemaPROCESSLIST表查看;

  • 長(zhǎng)連接
    在連接在建立之后依疼,就一直打開痰腮,后續(xù)請(qǐng)求可以重用此連接÷砂眨基本步驟是:連接→數(shù)據(jù)傳輸→維護(hù)連接→數(shù)據(jù)傳輸..→關(guān)閉連接膀值。
    優(yōu)勢(shì):建立連接的過程通常是比較復(fù)雜,使用長(zhǎng)連接可以避免頻繁建立連接的開銷误辑;
    劣勢(shì):維護(hù)長(zhǎng)連接是需要消耗內(nèi)存的沧踏。如果使用過多長(zhǎng)連接,會(huì)消耗大量?jī)?nèi)存資源巾钉,連接太少會(huì)影響用戶的響應(yīng)時(shí)間翘狱。

  • 短連接
    執(zhí)行操作后就關(guān)閉連接∨椴裕基本就是每一次操作數(shù)據(jù)庫潦匈,都要打開和關(guān)閉數(shù)據(jù)庫連接,基本步驟是:連接→數(shù)據(jù)傳輸→關(guān)閉連接赚导。
    優(yōu)勢(shì):用完即斷历等,不會(huì)占用過多內(nèi)存;適用高并發(fā)情況下的請(qǐng)求辟癌,保證效率寒屯;
    劣勢(shì):建立和銷毀連接開銷大,在高并發(fā)情況下瞬時(shí)請(qǐng)求過大容易造成內(nèi)存資源緊張黍少;

不同場(chǎng)景下有不同的選擇寡夹,沒有絕對(duì)正確只有適合項(xiàng)目的,JAVA中配合JDBC的連接池一般情況下是推薦使用長(zhǎng)連接厂置;長(zhǎng)連接的連接時(shí)長(zhǎng)是通過wait_timeout控制菩掏;

線程管理也是在這個(gè)模塊,可以使用show variables like 'thread%'查看相關(guān)參數(shù)昵济;

-------------------------
thread_cache_size      28
thread_handling        one-thread-per-connection
thread_stack           262144
-------------------------
  1. thread_handling表示線程配置模型
  • One-thread-per-connection
    每個(gè)客戶端的連接都對(duì)應(yīng)著一個(gè)線程智绸,相應(yīng)的操作也在同一個(gè)線程野揪。請(qǐng)求結(jié)束后,銷毀線程瞧栗,這種方式在高并發(fā)情況下斯稳,會(huì)導(dǎo)致線程的頻繁創(chuàng)建和釋放;
  • No-Threads
    在主線程上面處理連接
  • Pool-of-threads
    使用線程池迹恐,會(huì)在服務(wù)器上維護(hù)了一個(gè)線程池挣惰,避免為每個(gè)連接都創(chuàng)建銷毀一個(gè)線程。
  1. thread_cache_size
    服務(wù)器最大緩存的線程數(shù)以供重用殴边。當(dāng)客戶端斷開連接時(shí)憎茂,如果客戶端緩存的線程少于thread_cache_size,則將其放入緩存中 锤岸。當(dāng)客戶端有新的連接時(shí)先去從高速緩存中獲取的線程來滿足線程請(qǐng)求竖幔,并且僅當(dāng)高速緩存為空時(shí)才創(chuàng)建新線程。
    默認(rèn)值:8 + (max_connections / 100)
show global status like 'thread%'
-------------------------
Threads_cached         13    當(dāng)前線程池中緩存有多少空閑線程
Threads_connected      37    當(dāng)前的線程使用數(shù)量
Threads_created    196289    已經(jīng)創(chuàng)建的線程總數(shù)
Threads_running         1    當(dāng)前激活的線程數(shù)
-------------------------

可以通過高峰期查看Threads_createdThreads_created調(diào)整thread_cache_size是偷;
根據(jù)物理內(nèi)存推薦值(網(wǎng)上都這么說) 1G->8; 2G->16;3G->32; >3G->64

參考來自MySQL官方文檔

查詢緩存

Query Cache是用來緩存所執(zhí)行的SELECT語句以及該語句的結(jié)果集赏枚,MySql在實(shí)現(xiàn)Query Cache的具體技術(shù)細(xì)節(jié)上類似典型的KV存儲(chǔ),就是將SELECT語句和該查詢語句的結(jié)果集做了一個(gè)HASH映射并保存在一定的內(nèi)存區(qū)域中晓猛;如果緩存命中饿幅,將省略優(yōu)化器和執(zhí)行器的相關(guān)步驟,效率極高戒职;
查詢緩存的失效非常頻繁栗恩,只要有對(duì)一個(gè)表的更新,這個(gè)表上所有的查詢緩存都會(huì)被清空洪燥。從MySQL5.7.20就不被推薦使用磕秤,而在MySQL8中已經(jīng)刪除該模塊了;只有在特定的靜態(tài)表中才推薦使用捧韵;

show global status like 'Qcache%'
-------------------------
Qcache_free_blocks        1    緩存池中空閑塊的個(gè)數(shù)
Qcache_free_memory  1031832    緩存中空閑內(nèi)存量
Qcache_hits               0    緩存命中次數(shù)
Qcache_inserts            0    緩存寫入次數(shù)
Qcache_lowmem_prunes      0    因內(nèi)存不足刪除緩存次數(shù)
Qcache_not_cached   1329826476 查詢未被緩存次數(shù)
Qcache_queries_in_cache   0    當(dāng)前緩存中緩存的SQL數(shù)量
Qcache_total_blocks       1    緩存總block數(shù)
-------------------------

query_cache_type可以設(shè)置為0(緩存禁用)或者2(通過SQL_CACHE指定需要緩存的查詢)市咆;
打開查詢緩存對(duì)讀和寫操作都會(huì)帶來額外消耗:讀查詢?cè)陂_始之前必須先檢查是否命中緩存;如果這個(gè)讀查詢可以被緩存再来,那么當(dāng)完成執(zhí)行后蒙兰,需要將結(jié)果存入緩存;每次寫入操作時(shí)芒篷,需要將對(duì)應(yīng)表的所有緩存都設(shè)置失效搜变。如果緩存較大或碎片很多,則會(huì)帶來很大消耗针炉。

優(yōu)化器

在創(chuàng)建內(nèi)部分析樹之后挠他,MySQL應(yīng)用了各種優(yōu)化技術(shù)。這些技術(shù)可以包括篡帕,重寫查詢殖侵,掃描表的順序以及選擇要使用的正確索引贸呢。對(duì)于連接查詢,MySQL優(yōu)化器調(diào)查的可能計(jì)劃數(shù)量隨著查詢中引用的表的數(shù)量呈指數(shù)增長(zhǎng)拢军。對(duì)于少量表(通常小于7到10)楞陷,這不是問題。但是朴沿,當(dāng)提交較大的查詢時(shí)猜谚,在查詢優(yōu)化中花費(fèi)的時(shí)間可能很容易成為服務(wù)器性能的主要瓶頸败砂。

更靈活的查詢優(yōu)化方法使用戶能夠控制優(yōu)化器在搜索最佳查詢?cè)u(píng)估計(jì)劃時(shí)的詳盡程度赌渣。一般的想法是,優(yōu)化器調(diào)查的計(jì)劃越少昌犹,編譯查詢所花費(fèi)的時(shí)間就越少坚芜。另一方面,由于優(yōu)化器會(huì)跳過某些計(jì)劃斜姥,因此可能無法找到最佳計(jì)劃鸿竖。

查詢語句更新流程

InnoDB

InnoDB是一種平衡高可靠性和高性能的通用存儲(chǔ)引擎。在MySQL 5.7中铸敏,InnoDB是默認(rèn)的MySQL存儲(chǔ)引擎缚忧。
優(yōu)勢(shì)
DML操作遵循ACID(原子性,一致性杈笔,隔離性和持久性)模型闪水,具有提交,回滾和崩潰恢復(fù)功能的事務(wù)來保護(hù)用戶數(shù)據(jù)蒙具。
行級(jí)鎖定和Oracle風(fēng)格的一致性讀取可提高多用戶并發(fā)性和性能球榆。
InnoDB表格將數(shù)據(jù)排列在磁盤上,以根據(jù)主鍵優(yōu)化查詢 禁筏。每個(gè)InnoDB表都有一個(gè)稱為聚簇索引的主鍵索引 持钉,用于組織數(shù)據(jù)以最小化主鍵查找的I / O.
InnoDB表的DML語句在事務(wù)的上下文中操作,因此它們的效果可以作為單個(gè)單元提交回滾篱昔。

  • DML
    數(shù)據(jù)操縱語言每强,一組 SQL執(zhí)行語句 INSERTUPDATE州刽、 DELETESELECT ... FOR UPDATE;
innodb架構(gòu)
InnoDB內(nèi)存結(jié)構(gòu)
緩沖池 Buffer Pool

緩沖池是主存儲(chǔ)器中的一個(gè)區(qū)域舀射,用于在訪問時(shí)緩存表和索引數(shù)據(jù);所有的對(duì)數(shù)據(jù)庫的操作都是先對(duì)緩沖池中的操作怀伦,有個(gè)后臺(tái)線程定期修改到磁盤里面脆烟;為了提高緩存管理的效率,緩沖池是由多個(gè)數(shù)據(jù)頁(頁面可以包括一行或多行數(shù)據(jù)房待,每個(gè)頁16k默認(rèn)innodb_page_size=16k)構(gòu)成的一個(gè)鏈表邢羔,使用LRU(least recently used)算法管理鏈表驼抹;

如果對(duì)一個(gè)數(shù)據(jù)頁進(jìn)行修改后需要讀取其內(nèi)容,則直接在內(nèi)存中讀取拜鹤,加速了讀取數(shù)據(jù)的效率框冀,通過show engine innodb status可以直接查看Buffer Pool的命中率Buffer pool hit rate,所謂的命中率就是訪問的數(shù)據(jù)頁在內(nèi)存中不需要到磁盤加載的敏簿;

數(shù)據(jù)頁淘汰算法-LRU


當(dāng)緩沖池中的數(shù)據(jù)頁全部被使用了明也,這時(shí)候需要從磁盤加載一個(gè)新的頁面時(shí)肯定需要淘汰掉某個(gè)頁面,innodb buffer pool使用的是最近最少使用(LRU)算法惯裕,同時(shí)順便對(duì)這個(gè)算法修改了一下温数;
整個(gè)鏈表分為Young區(qū)和Old區(qū),根據(jù)參數(shù)innodb_old_blocks_pct來決定它們的大小蜻势,默認(rèn)值3/8為Old區(qū)撑刺,5/8為Young區(qū);
當(dāng)一個(gè)新的數(shù)據(jù)頁進(jìn)來的時(shí)候握玛,默認(rèn)的位置是放在old區(qū)的head够傍,當(dāng)這個(gè)數(shù)據(jù)頁連續(xù)被訪問的時(shí)間超過1s,會(huì)被移動(dòng)到Y(jié)oung區(qū)的頭部挠铲,如果這個(gè)數(shù)據(jù)頁連續(xù)被訪問的時(shí)間小于1s冕屯,則位置不變,這個(gè)1s是由參數(shù)innodb_old_blocks_time控制的拂苹,這樣做的好處是假如一個(gè)大表全表掃描需要訪問很多的數(shù)據(jù)頁安聘,但是每個(gè)數(shù)據(jù)頁訪問的時(shí)間都是很短且訪問一次后再次訪問的可能性很小,所以放在Old區(qū)能夠更快的淘汰掉釋放空間醋寝,不至于讓Buffer Pool中常被訪問的熱點(diǎn)數(shù)據(jù)頁被意外淘汰搞挣,能有效提升緩沖池的命中率;

  • InnoDB緩沖池里面有什么音羞?
    數(shù)據(jù)緩存 - InnoDB數(shù)據(jù)頁面囱桨;
    索引緩存 - 索引數(shù)據(jù);
    緩沖數(shù)據(jù) - 臟頁: 在內(nèi)存中修改但尚未刷新(寫入)到數(shù)據(jù)磁盤的數(shù)據(jù)嗅绰;
    內(nèi)部結(jié)構(gòu) - InnoDB緩沖池還存儲(chǔ)內(nèi)部結(jié)構(gòu)舍肠,如自適應(yīng)哈希索引,行級(jí)鎖等窘面;

相關(guān)配置:

show global status like 'innodb_buffer_pool_read%'
------------------------------------------------
Innodb_buffer_pool_read_requests    57119197605 表示從內(nèi)存中讀取邏輯的請(qǐng)求數(shù)
Innodb_buffer_pool_reads              471363395 表示InnoDB緩沖池?zé)o法滿足的請(qǐng)求數(shù)翠语;需要從磁盤中讀取
------------------------------------------------
show global status like 'innodb_buffer_pool_page%'
------------------------------------------------
Innodb_buffer_pool_pages_data          8183 顯示臟和干凈的數(shù)據(jù)和索引頁面的數(shù)量
Innodb_buffer_pool_pages_dirty           26 顯示在內(nèi)存中修改但尚未寫入數(shù)據(jù)文件的InnoDB緩沖池?cái)?shù)據(jù)頁數(shù)
Innodb_buffer_pool_pages_flushed    2729397 表示從InnoDB緩沖池中刷新臟頁的請(qǐng)求數(shù)
Innodb_buffer_pool_pages_free             0 顯示InnoDB緩沖池中的空閑頁面
Innodb_buffer_pool_pages_misc             8 顯示繁忙的頁面數(shù)
Innodb_buffer_pool_pages_total         8191
------------------------------------------------

推薦的計(jì)算公式 Performance =  innodb_buffer_pool_reads / innodb_buffer_pool_read_requests * 100 ,值當(dāng)然是越小越好;

相關(guān)參數(shù):

  • innodb_buffer_pool_size
    直接決定了緩沖池的大小财边,非常重要的配置項(xiàng)肌括,MySQL5.7以后可以通過
    set global innodb_buffer_pool_size=xx動(dòng)態(tài)配置,在專用數(shù)據(jù)庫服務(wù)器上面可以設(shè)置成最大內(nèi)存的50-80%酣难;
show status where variable_name='InnoDB_buffer_pool_resize_status';

可以監(jiān)控在線緩沖池調(diào)整進(jìn)度谍夭,也可以在mysql錯(cuò)誤日志中查看黑滴;

  • innodb_buffer_pool_instances
    buffer pool將劃分為多個(gè)實(shí)例以提高系統(tǒng)并發(fā)性, 減少線程間讀寫緩存的爭(zhēng)用。當(dāng)innodb_buffer_pool_size大于 1GB 時(shí), innodb_buffer_pool_instances默認(rèn)為 8紧索;
Change Buffer

當(dāng)對(duì)二級(jí)索引進(jìn)行insert袁辈、update、delete時(shí)珠漂,如果目標(biāo)數(shù)據(jù)頁在內(nèi)存則直接對(duì)內(nèi)存進(jìn)行操作晚缩,但是如果數(shù)據(jù)頁不在內(nèi)存時(shí),需要把數(shù)據(jù)頁從磁盤讀入內(nèi)存里面媳危,ChangeBuffer的作用是緩存對(duì)二級(jí)索引的數(shù)據(jù)操作(主鍵索引是用不上的)荞彼,并且在數(shù)據(jù)頁被加載進(jìn)buffer pool時(shí)將change buffer中的操作合并,這樣一來可以避免很多對(duì)磁盤的隨機(jī)IO济舆;另外ChangeBuffer是可以持久化的卿泽,意味著數(shù)據(jù)是會(huì)被寫在磁盤中莺债,實(shí)際上ChangeBuffer是儲(chǔ)存在ibdata1(系統(tǒng)表空間)里面的滋觉;

磁盤一個(gè)I/O請(qǐng)求所花費(fèi)的時(shí)間=尋道時(shí)間+旋轉(zhuǎn)延遲+數(shù)據(jù)傳輸時(shí)間;
順序IO是指讀取和寫入操作基于邏輯塊逐個(gè)連續(xù)訪問來自相鄰地址的數(shù)據(jù)齐邦。在順序IO訪問中椎侠,磁盤所需的磁道搜索時(shí)間顯著減少,因?yàn)樽x/寫磁頭可以以最小的移動(dòng)訪問下一個(gè)塊措拇。
隨機(jī)IO是指讀寫操作時(shí)間連續(xù)我纪,但訪問地址不連續(xù),磁頭在兩次IO操作之間需要作比較大的移動(dòng)動(dòng)作才能重新開始讀/寫數(shù)據(jù)丐吓。

SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
       WHERE PAGE_TYPE LIKE 'IBUF%') AS change_buffer_pages, 
       (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS total_pages,
       (SELECT ((change_buffer_pages/total_pages)*100)) 
       AS change_buffer_page_percentage;
-------------------------------------
change_buffer_pages               44 
total_pages                     8191
change_buffer_page_percentage 0.5372
-------------------------------------

Change Buffer使用的是Innodb buffer pool里面的內(nèi)存浅悉,所以最大值為buffer pool的大小,使用參數(shù)innodb_change_buffer_max_size來控制

show variables like 'innodb_change%'
-------------------------------------
innodb_change_buffer_max_size  25    
innodb_change_buffering       all
-------------------------------------
innodb_change_buffer_max_size

25表示max size為innodb buffer pool的25%

innodb_change_buffering
  • none:不使用Change Buffer
  • inserts:在insert操作的時(shí)候使用
  • deletes:在delete和update操作的時(shí)候使用
  • changes:包括inserts和deletes
  • purges:在后臺(tái)使用purges的時(shí)候使用
  • all:包括inserts券犁、deletes术健、changes、purges
日志緩存區(qū) log buffer

log buffer儲(chǔ)存要寫入磁盤上日志文件的數(shù)據(jù)的內(nèi)存區(qū)域粘衬;日志緩沖區(qū)大小由innodb_log_buffer_size變量定義 荞估;默認(rèn)大小為16MB。日志緩沖區(qū)的內(nèi)容會(huì)定期刷新到磁盤稚新。大的日志緩沖區(qū)使大的事務(wù)能夠運(yùn)行勘伺,而無需在事務(wù)提交之前將重做日志數(shù)據(jù)寫入磁盤。因此如果有大量更新褂删,插入或刪除的事務(wù)飞醉,增加日志緩沖區(qū)的大小可以節(jié)省磁盤I / O。
相關(guān)配置:

  • innodb_flush_log_at_trx_commit
    • 0:每秒寫入日志并將其刷新到磁盤一次屯阀;未刷新日志的事務(wù)可能會(huì)在崩潰中丟失缅帘。
    • 1:在每次事務(wù)提交時(shí)寫入日志并刷新到磁盤
    • 2:在每次事務(wù)提交后寫入日志噪裕,并每秒刷新一次磁盤;未刷新日志的事務(wù)可能會(huì)在崩潰中丟失
InnoDB磁盤結(jié)構(gòu)

Innodb是按照表空間(Tablespace)的結(jié)構(gòu)進(jìn)行儲(chǔ)存的股毫;

共享表空間(System Tablespace)

Innodb的所有數(shù)據(jù)保存在一個(gè)單獨(dú)的表空間里面膳音,而這個(gè)表空間可以由很多個(gè)文件組成,一個(gè)表可以跨多個(gè)文件存在铃诬,所以其大小限制不再是文件大小的限制祭陷,而是其自身的限制。從Innodb的官方文檔中可以看到趣席,其表空間的最大限制為64TB兵志;
可以在配置文件中找到datadir所配置的路徑,默認(rèn)的共享表空間文件名叫ibdata1;

獨(dú)立表空間(File-Per-Table Tablespace)

每個(gè)InnoDB表都存儲(chǔ)在自己獨(dú)立的表空間數(shù)據(jù)文件宣肚。.ibd文件儲(chǔ)存數(shù)據(jù)和索引想罕,.frm儲(chǔ)存表結(jié)構(gòu)數(shù)據(jù);

不同處:
truncate或者drop儲(chǔ)存在獨(dú)立表空間的表時(shí)能回收磁盤空間霉涨,而truncate或者drop儲(chǔ)存在系統(tǒng)表空間的表時(shí)會(huì)在ibdata文件內(nèi)部標(biāo)記可用空間按价,并不會(huì)縮小文件大小笙瑟;
獨(dú)立表空間可以使用optimize table來壓縮或重新創(chuàng)建表文件楼镐;當(dāng)運(yùn)行這條命令時(shí), InnoDB創(chuàng)建一個(gè)新的 .ibd具有臨時(shí)名稱的文件往枷,該文件存儲(chǔ)的實(shí)際數(shù)據(jù)是該表所需要的空間框产。優(yōu)化完成后,InnoDB刪除舊.ibd文件并將其替換為新文件错洁。

雙寫緩存區(qū)(Doublewrite Buffer)

首先需要理解一些概念秉宿,磁盤物理操作的基本單位是扇區(qū),是真實(shí)存在的物理單位屯碴,在linux下使用fdisk -l命令可以了解該磁盤的基本信息比如

每個(gè)扇區(qū)大小為512bytes

操作系統(tǒng)與磁盤之間數(shù)據(jù)交流的最小單位是磁盤塊描睦,是操作系統(tǒng)抽象出來的一個(gè)概念;linux內(nèi)核要求 block size = sector size * 2^n窿锉,即是扇區(qū)的整數(shù)倍酌摇;linux可以通過tune2fs -l /dev/vda1|grep Block size查看block size大小(一般是Block size: 4096),操作系統(tǒng)是以頁管理的嗡载,一般大小為4k;

而在Innodb里面窑多,page是存儲(chǔ)的最基本結(jié)構(gòu),也是對(duì)磁盤管理的最小單位洼滚;可以使用show variables like 'innodb_page_size' 查看埂息,一般為16k;
任何數(shù)據(jù)庫IO操作最終都是體現(xiàn)在對(duì)扇區(qū)的IO操作上面,比如現(xiàn)在需要對(duì)一頁(16k)的數(shù)據(jù)寫入磁盤千康,因?yàn)榇疟P扇區(qū)的大小為512bytes享幽,所以是需要對(duì)多個(gè)扇區(qū)進(jìn)行操作,當(dāng)這個(gè)操作進(jìn)行到一半時(shí)發(fā)生數(shù)據(jù)庫宕機(jī)或者掉電拾弃,就會(huì)出現(xiàn)數(shù)據(jù)頁只有部分寫入磁盤值桩,這種情況叫做頁斷裂(partial write);

Doublewrite buffer是Innodb表空間內(nèi)部分配的一片緩沖區(qū)且與數(shù)據(jù)頁一樣有物理存儲(chǔ)空間,儲(chǔ)存在共享表空間中豪椿。當(dāng)臟頁的數(shù)據(jù)flush到磁盤時(shí)先將數(shù)據(jù)寫入doublewrite buffer中奔坟,然后在fsync到磁盤上,如果期間發(fā)生掉電并且導(dǎo)致page數(shù)據(jù)損壞搭盾,可以通過buffer內(nèi)的數(shù)據(jù)進(jìn)行恢復(fù)咳秉;因?yàn)閷懭雂oublewrite buffer和數(shù)據(jù)頁落盤的時(shí)間點(diǎn)是不一樣的所以不會(huì)出現(xiàn)兩個(gè)都是損壞的情況;

當(dāng)然雙寫會(huì)帶來一定的消耗鸯隅,但是不是兩倍于直接落盤澜建,因?yàn)閿?shù)據(jù)頁的數(shù)據(jù)是做為一個(gè)大的連續(xù)的塊(chunk)順序?qū)懭腚p寫緩存區(qū)中,只需要一次fsync蝌以;

重做日志(Redo Log)

InnoDB記錄了對(duì)數(shù)據(jù)文件的物理更改炕舵,并保證總是日志先行,也就是所謂的WAL(Write-Ahead Logging)饼灿,即在持久化數(shù)據(jù)文件前幕侠,保證之前的redo日志已經(jīng)寫到磁盤帝美。redo log默認(rèn)在磁盤上由兩個(gè)名為ib_logfile0ib_logfile1(默認(rèn)是兩個(gè))的文件物理表示碍彭,MySQL以循環(huán)方式寫入這兩個(gè)文件;

  • 為什么需要redo log
    當(dāng)修改innodb表上某行數(shù)據(jù)時(shí)悼潭,如果該行不在內(nèi)存中則需要將該數(shù)據(jù)頁從磁盤讀入到內(nèi)存去然后在內(nèi)存中更新該行庇忌,現(xiàn)在內(nèi)存中的數(shù)據(jù)頁與磁盤中就不一致了,把這種內(nèi)存數(shù)據(jù)頁與磁盤數(shù)據(jù)頁不一致的數(shù)據(jù)頁稱為臟頁(dirty page)舰褪,DB需要把臟頁數(shù)據(jù)寫入磁盤皆疹,但是如果每一次更新數(shù)據(jù)就會(huì)帶來一次磁盤操作的話那么機(jī)器肯定撐不住占拍;所以說mysql會(huì)把標(biāo)記為臟頁的數(shù)據(jù)頁儲(chǔ)存在一個(gè)flush list里面略就,用一個(gè)專門的后臺(tái)線程定時(shí)刷臟;那么如果在mysql還沒有刷臟的時(shí)候數(shù)據(jù)庫掛了怎么辦呢晃酒,所以就需要redo log表牢;
  • 儲(chǔ)存著什么
    日志緩存區(qū)(redo log buffer)日志文件(redo log file)構(gòu)成,redo log是物理日志贝次,保存的是數(shù)據(jù)頁上被修改的值崔兴;還有一種是邏輯日志,保存的是SQL語句比如binlog;

redo log的寫入過程

一開始是存在于redolog buffer敲茄,這部分是屬于mysql進(jìn)程內(nèi)存中的位谋,所以寫這部分的效率是很高的;在一個(gè)事務(wù)的更新過程中redolog可能是要寫多次的堰燎,所以在commit前日志是保存在redolog buffer中掏父,等待commit時(shí)在寫到redolog file中;

其實(shí)寫redolog file也不是直接寫到磁盤秆剪,是寫到文件系統(tǒng)的page cahce里面损同,最后才是持久化到磁盤,fsync一般來說是IO性能的瓶頸鸟款;

page cache用來緩存文件數(shù)據(jù)膏燃,是屬于操作系統(tǒng)的緩存,如果想要持久化到磁盤中需要使用fsync何什;


除了后臺(tái)線程會(huì)每秒刷一次之外组哩,還有兩種情況會(huì)主動(dòng)寫盤;

  • redo log buffer 即將占用innodb_log_buffer_size的一半的時(shí)候处渣,后臺(tái)線程會(huì)主動(dòng)寫盤伶贰,但是也只是寫入到page cache里面并沒有使用fsync;
  • 當(dāng)innodb_flush_log_at_trx_commit是1的時(shí)候罐栈,如果并行的事務(wù)提交黍衙,那么會(huì)將redo log buffer的所有日志(包括其他線程只寫到一半的日志)都會(huì)持久化到磁盤,因?yàn)閞edo log buffer是共享的荠诬;
show variables like 'innodb_log%'
-------------------------------------
innodb_log_buffer_size  16777216  寫入日志文件緩沖區(qū)的字節(jié)
innodb_log_file_size    50331648  ib_logfile文件的大小
innodb_log_files_in_group      2  控制日志文件數(shù)
-------------------------------------

參考

How to allocate innodb_buffer_pool_size in MySQL?
頁斷裂(partial write)與doublewrite技術(shù)
IO系統(tǒng)性能之一:衡量性能的幾個(gè)指標(biāo)
磁盤I/O那些事
MySQL · 引擎特性 · InnoDB redo log漫游
詳細(xì)分析MySQL事務(wù)日志(redo log和undo log)
MySQL · 引擎特性 · Innodb change buffer介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末琅翻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子柑贞,更是在濱河造成了極大的恐慌方椎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钧嘶,死亡現(xiàn)場(chǎng)離奇詭異棠众,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)有决,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門闸拿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人书幕,你說我怎么就攤上這事新荤。” “怎么了按咒?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵迟隅,是天一觀的道長(zhǎng)但骨。 經(jīng)常有香客問我,道長(zhǎng)智袭,這世上最難降的妖魔是什么奔缠? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮吼野,結(jié)果婚禮上校哎,老公的妹妹穿的比我還像新娘。我一直安慰自己瞳步,他們只是感情好闷哆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著单起,像睡著了一般标捺。 火紅的嫁衣襯著肌膚如雪够吩。 梳的紋絲不亂的頭發(fā)上政勃,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天鸽疾,我揣著相機(jī)與錄音,去河邊找鬼测蘑。 笑死灌危,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碳胳。 我是一名探鬼主播勇蝙,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挨约!你這毒婦竟也來了味混?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤烫罩,失蹤者是張志新(化名)和其女友劉穎惜傲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贝攒,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年时甚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隘弊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荒适,死狀恐怖梨熙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刀诬,我是刑警寧澤咽扇,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響质欲,放射性物質(zhì)發(fā)生泄漏树埠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一嘶伟、第九天 我趴在偏房一處隱蔽的房頂上張望怎憋。 院中可真熱鬧,春花似錦九昧、人聲如沸绊袋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽癌别。三九已至,卻和暖如春蹋笼,著一層夾襖步出監(jiān)牢的瞬間规个,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工姓建, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诞仓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓速兔,卻偏偏與公主長(zhǎng)得像墅拭,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涣狗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容