1. 程式人生 > 其它 >MySQL筆記六-innodb引擎的關鍵特性

MySQL筆記六-innodb引擎的關鍵特性

本節內容同 MySQL筆記六-innodb儲存引擎是一起的,由於內容比較多,排版不想弄,就單獨放一節,但是大序號不變,都是六 insert buffer insert buffer需要滿足的條件 :insert的 索引是非唯一輔助索引。 什麼是insert buffer?簡單的說就是當insert一條資料,在更新輔助索引樹時,如果需要插入的資料頁不在記憶體裡,則將資料放到insert buffer裡,並返回insert成功(實際上沒有),等到一定條件下,將多個insert命令一起執行,減少與磁碟的互動,提高insert效能。 為什麼需要insert buffer?由於主鍵一般是自增的,當insert一條資料時是按照主鍵順序存放,這是insert資料是很快的,因為只需要順序存放即可。可是對於表中的輔助索引而言,insert的資料可就不是順序的了,innodb需要一個個的比對索引資料的大小,再將索引資料存放在合適的位置(這裡插入的不是資料,而是索引欄位的資料和對應的主鍵值),如果每一條資料都插入都落盤,就存在大量的隨機io,將嚴重的拖慢insert速度,更嚴重的是一張表上很可能不止一個輔助索引,更更嚴重的是,還會存在頁分裂,這都會對insert效率產生負面的影響。所以,需要insert buffer insert buffer 為何需要滿足以上的條件
以上的條件有兩個關鍵,1,非唯一索引;2,輔助索引。 關於第一的關鍵點,假設索引是唯一的,那麼再插入索引資料時,為了保證唯一性,需要將整個索引樹的資料都遍歷一遍,而此操作就會伴隨著大量的io;問:這些io都是順序io啊,輔助索引表的存放是順序的,順序io不是很快麼。答,1,順序io確實很快,但是如果資料量很大,即使是順序io也會耗時久;2,既然已經把索引資料都load 進記憶體了,哪還有使用insert buffer的必要麼,直接insert不就行了。 關於第二個關鍵點,假設不是輔助索引,那就是主鍵,主鍵都是有唯一性要求,同第一點要求。 PS:主鍵是UUID型別呢,那不是更不行,又唯一,又無序 insert buffer是怎麼是實現的?
insert buffer的實現是通過一顆 B+ tree實現,該樹存放在共享表空間,即ibdata1裡。它的非葉子節點的結構是,
space id marker offset
其中space id是表的唯一表示,marker是相容老版本的標誌,offset是表示該頁的偏移量,這三個欄位結合在一起稱之為 search key。這個search key可以用於標識 某個具體的頁。而非葉子節點的結構是
space id marker offset metadata secondary index record
前面三個欄位一樣,metadata欄位記錄了每個記錄進入insert buffer的順序。secondary index record 欄位記錄了實際insert的記錄。 那麼insert buffer的流程就是這樣,一條insert sql進來,首先判斷是否滿足使用insert buffer的條件,是則生成對應的 search key,放進tree裡,然後再將這條記放到這個search key下的葉子節點中。 什麼時候merge insert buffer呢?
1,當輔助索引頁被讀到記憶體裡時,這是可以去insert buffer B+ tree裡查詢是否有屬於此頁的insert buffer 記錄,如果有則merge,等同與搭順風車。 2,當輔助索引頁空間緊張時,當檢測到某個輔助索引頁可用空間小於1/32時,需要強制將其讀進記憶體進行頁分裂,此時又可以搭便車 3,在Master thread 中會主動機進行merge insert buffer 操作,不同的是,此次merge會一次隨機merge多個頁,具體由srv_innodb_io_capacity引數控制。 ps 還有個特殊頁名為 insert buffer bitmap,每個此種頁追蹤16384個輔助索引頁,它會記錄每個輔助索引頁的剩餘空間和是否有記錄在insert buffer裡。所以merge insert buffer 的三種場景其實都需要 insert buffer bitmap頁參與,它很重要。 insert buffer 的發展 目前insert buffer已經升級成change buffer,innodb可以對DML操作,比如insert ,update,delete都進行快取,對應的就是insert buffer,update buffer ,delete buffer,實現和關鍵都一樣,就不深入了。其中提一嘴delete buffer,還記得之前提到過的隱藏欄位麼,每一行都有個類似is_delete的隱藏欄位,當update/delete 刪除一條資料時,實際上修改is_delete欄位來標識刪除,實際時通過purge thread 完成實際的刪除操作。 doublewrite 什麼是doublewrite如果innodb正在寫入某個頁到表中時,發生宕機,此時頁只寫了一半,這種情況稱之為 partial page write(部分寫失效),是有可能導致數丟失的。crash recover時,由於頁本身已經損壞,即使是rodo log頁無法修復,因為redo log記錄的是對頁的物理操作,比如在page 1 offset 100的位置寫 "a" 但此時頁本身已經損壞,其他位置的資料已經丟失,所以僅有redo log無法修復。所以再使用redo log 恢復之前,需要先找到該頁的副本,然後還原該頁,最後再apply redo log恢復資料。這種操作就是 double write 為什麼需要doublewrite上文說了 怎麼實現 doublewrite? doublewrite 由兩部分組成,第一部分是 doublewrite buffer,大小是2MB,這是在記憶體裡的。第二部分在共享表空間裡,大小也是2MB,這是在磁盤裡的。當需要flush dirty page時,不是直接刷進磁碟,而是通過 memcpy 函式將髒頁 cpoy到 doublewrite buffer裡,這是記憶體操作,很快;然後通過doublewrite buffer分兩次,每次1MB的,順序的將資料寫入共享表空間,這是順序寫,也很快;最後立即呼叫fsync函式重新整理磁碟,這是隨機寫,就慢了,注意fsync到磁碟的資料是 doublewrite buffer裡的資料,不是原來髒頁裡的資料。如果發生宕機導致頁損壞,就可以使用共享表空間裡的資料來恢復資料頁,然後用redo log 恢復資料。 AHI 自適應雜湊索引 AHI是由innodb自己為了加速某些查詢條件建立的索引,自適應是因為此操作只能由innodb控制,人工無法干預,當然你有關閉此功能的權利,雜湊索引就是雜湊索引,是一種如果合適那就最快的索引。 建立AHI的條件 1,以某種查詢條件 連續 執行了 100次,比如where a= 1234,注意是連續,不是總共。2,頁通過 某種查詢條件連續訪問了 N次,N=頁中的記錄/16,注意是連續,不是總共。 效能上使用AHI 將提高2倍的讀寫效能。 非同步IO 非同步io可以類比下merge insert buffer,非同步IO也有個 merge io操作,就是將多個io合併成一個,比如io1 訪問page 1 offset 100~200,io 2 訪問page 1 offset 300~400,io3 訪問 page 1 offset 200 ~300,那麼就可以merge 這三個io操作合成 io 訪問page 1 offset 100~400,此功能可手動關閉 重新整理臨接頁 如名字所示,就是在重新整理某個髒頁時,檢查下同區(extent)的所有頁有沒有頁需要重新整理,如果有就一起重新整理,好處是將多個io操作合併成一個。但是有一下兩個問題,1,順帶重新整理的頁可能很快又髒了,2,現在普遍使用ssd,iops足夠高。歸根結底,啟用此功能弊大於利,故可以考慮關閉此功能。如果使用sas,可以開啟,不過應該很少了吧。