1. 程式人生 > >Mysql技術內幕——InnoDB儲存引擎

Mysql技術內幕——InnoDB儲存引擎

一.mysql體系結構和儲存引擎

1.1、資料庫和例項的區別

資料庫:物理作業系統或其他形式檔案型別的集合。在mysql下資料庫檔案可以是frm,myd,myi,ibd結尾的檔案。

     資料庫例項:由資料庫後臺程序/執行緒以及一個共享記憶體區組成。資料庫例項才是真正用來操作資料庫檔案的。

     mysql資料庫是單程序多執行緒的程式,與sql server比較類似。也就是說,Mysql資料庫例項在系統上的表現就是一個程序。

1.2、mysql的體系結構

mysql由連線池元件、管理服務和工具元件、sql介面組建、查詢分析器元件、優化器元件、快取元件、外掛是儲存引擎、物理檔案。

1.3、mysql儲存引擎

  1.3.1、innodb儲存引擎,特點支援外來鍵、行鎖、非鎖定讀(預設情況下讀取不會產生鎖)、mysql-4.1開始支援每個innodb引擎的表單獨放到一個表空間裡。innodb通過使用MVCC來獲取高併發性,並且實現sql標準的4種隔離級別,同時使用一種被稱成next-key locking的策略來避免換讀(phantom)現象。除此之外innodb引擎還提供了插入快取(insert buffer)、二次寫(double write)、自適應哈西索引(adaptive hash index)、預讀(read ahead)等高效能技術。

  1.3.2、myisam儲存引擎,myisam特點是不支援事物,適合olap應用,myisam表由MYD和MYI組成。mysql-5.0版本之前,myisam預設支援的表大小為4G,從mysql-5.0以後,myisam預設支援256T的表單資料。myisam只快取索引資料。

  1.3.3、NDB儲存引擎,特點是資料放在記憶體中,mysql-5.1版本開始可以將非索引資料放到磁碟上。NDB之前的缺陷是join查詢是mysql資料庫層完成的,而不是儲存引擎完成的,複雜的join查詢需要巨大的網路開銷,速度很慢。當前mysql cluster7.2版本中已經解決此問題,join查詢效率提高了70倍。

  1.3.4、memeory儲存引擎,將資料放到記憶體中,預設使用hash索引,不支援text和blob型別,varchara是按照char的方式來儲存的。mysql資料庫使用memory儲存引擎作為臨時表還儲存中間結果集(intermediate result),如果中間集結果大於memorg表的容量設定,又或者中間結果集包含text和blog列型別欄位,則mysql會把他們轉換到myisam儲存引擎表而放到磁碟上,會對查詢產生效能影響。

  1.3.5、archive儲存引擎,壓縮能力較強,主要用於歸檔儲存。

  1.3.6、federated儲存引擎,不儲存資料,他指向一臺遠端mysql資料庫上的表。

  1.3.7、maria儲存引擎,myisam的後續版本,支援快取資料和索引,行鎖設計,支援mvcc,支援事務和非事務安全的選項,以及更好的BLOG字元型別的處理效能。

  1.3.8、其他儲存引擎,sphinx用於全文索引,infobright用於資料倉庫。

1.4連線Mysql

1.4.1、TCP/IP:基於網路的連線,連線進行許可權檢查。

     1.4.2、命名管道和共享記憶體:Windows系統上同一伺服器上的兩程序可通過命名管道連線,需在配置檔案中啟用--enable-named-pipe選項。

     1.4.3、Unix套接字:客戶端與服務端位於同一伺服器時才可使用,可以在my.cnf中指定-socket=/tmp/mysql.sock,連線時指定./mysql -S/tmp/mysql.sock。

二.InnoDB儲存引擎

2.2、innodb引擎架構

   InnoDB的多個記憶體塊組成了記憶體池,負責如下工作:

1).維護所有程序/執行緒需要訪問的多個內部資料結構。

  2).快取磁碟上的資料,方便快速的讀取,並且在對磁碟檔案的資料進行修改之前在這裡快取。

  3).重做日誌快取。

  後臺執行緒的主要作用是負責重新整理記憶體池中的資料,保證緩衝池中的記憶體快取是最近的資料,此外、將已經修改的資料檔案重新整理到磁碟檔案

  2.2.1、後臺執行緒

  innodb儲存引擎後臺有7個執行緒,—–4個IO執行緒(insert buffer thread,log thread,read thread,write thread),1個master thread,一個lock監控執行緒,一個錯誤監控執行緒。

  2.2.2、記憶體

  innodb儲存引擎記憶體由以下三個部分組成:緩衝池(buffer pool),重做日誌快取(redo log buffer),額外的記憶體池(additional memory pool)。可以使用 show engine innodb status來檢視innodb_buffer_pool的使用情況。

  innodb_buffer_pool_size:具體看,緩衝池中的資料庫型別有:索引頁、資料庫頁、undo頁、插入快取頁(insert buffer)、自適應hash(adaptive hashindex)、innodb儲存的鎖資訊(lock info)、資料字典資訊(data dictionary)。

     InnoDB工作方式:將資料檔案按頁(每頁16K)讀入InnoDBbuffer pool,然後按最近最少使用演算法(LRU)保留快取資料,最後通過一定頻率將髒頁重新整理到檔案。

2.3、master thread

  2.3.1、master thread原始碼分析



  2.3.2、master thread的潛在問題

  1、由於硬體的發展,現在的硬體效能已經提高了很多,如果innodb每秒最大重新整理100個髒頁,那麼效率會很低,為了解決這個問題,innodb plugin提供了一個引數innodb_io_capacity,用來表示磁碟IO的吞吐量,預設值是200,規則如下:在合併插入快取時,合併插入快取的數量為innodb_io_capacity的5%;在從緩衝區重新整理髒頁時,啥新髒頁的數量為innodb_io_capacity。

  2、關於innodb_max_dirty_pages_pct值的爭議,如果值過大,記憶體也很大或者伺服器壓力很大,那麼效率很降低,如果設定的值過小,那麼硬碟的壓力會增加,建議是在75-80.並且innodb plugin引進了innodb_adaptive_flushng(自適應的重新整理),該值影響每秒重新整理髒頁的數量。

2.4、關鍵特性,為innodb提高效能的技術

  2.4.1、插入快取

  當一個表有非聚集索引時,對於非聚集索引的葉子節點的插入不是順序的,這時候需要離散的訪問非聚集索引頁,效能就在這裡降低了,這是由於b+樹的原理導致的。插入快取就是用來解決這個問題的。

  對於非聚集索引的插入和更新操作,不是每一次都直接插入索引頁,而是先判斷插入的非聚集索引頁是否在快取中,如果在就直接插入,如果不在就放入到一個插入緩衝區中,好似欺騙資料庫這個非聚集索引已經插入到葉子節點了。然後再以一定的頻率插入快取和非聚集索引頁位元組點的合併操作。

  插入快取的使用需要滿足以下兩個條件(也就是非唯一的輔助索引):索引是輔助索引;索引不是唯一的。

  2.4.2、兩次寫

  兩次寫給innodb帶來的是可靠性,主要用來解決部分寫失敗(partial page write)。在應用重做日之前,我們需要一個頁的副本,當寫入失效發生時,先通過頁的副本來還原該頁,再進行重做,這就是doublewrite。

  doublewrite有兩部分組成,一部分是記憶體中的doublewrite buffer,大小為2M,另外一部分就是物理磁碟上的共享表空間中聯絡的128個頁,即兩個區,大小同樣為2M。當緩衝池的張也重新整理時,並不直接寫硬碟,而是回通過memcpy函式將髒頁先拷貝到記憶體中的doublewrite buffer,之後通過doublewrite buffer再分兩次寫,每次寫入1M到共享表空間的物理磁碟上,然後馬上呼叫fsync函式,同步磁碟。

  2.4.3、自適應哈西索引

  由於innodb不支援hash索引,但是在某些情況下hash索引的效率很高,於是出現了 adaptive hash index功能,innodb儲存引擎會監控對錶上索引的查詢,如果觀察到建立hash索引可以提高效能的時候,則自動建立hash索引。

2.5、啟動、關閉、恢復

innodb_fast_shutdown影響InnoDB表關閉。該引數有0、1、2三個引數。

  0 MySQL關閉時  完成所有的full purge和merge insertbuffer操作

     1預設值 只將緩衝池內的一些髒頁重新整理至磁碟

     2將日誌都寫入日誌檔案不會有任何事務丟失但下次啟動時會進行recovery

  innodb_force_recovery影響整個innodb儲存引擎的恢復狀況,該值預設為0,表示當需要恢復時,需要執行所有的恢復操作,當不能進行有效恢復時,如資料頁發生了corruption,mysql資料庫可能宕機,並把錯誤寫入錯誤日誌中。

三.檔案

3.1引數檔案

  Mysql例項可以不需要引數檔案,這是所有的引數值取決於編譯Mysql時指定的預設值和原始碼中指定引數的預設值。其引數檔案是Mysql.cnf。

3.1.1、什麼是引數

  引數是一個鍵/值對。可以使用show variables like命令檢視,也可以通過information_schema的GLOBAL_VARIABLES檢視來查詢。

3.1.2、引數型別

  引數檔案分為兩類:動態引數和靜態引數。動態引數意味著你可以在Mysql例項執行中進行更改;靜態引數說明在整個例項生命週期內都不得進行更改,好像是隻讀的。對於動態引數,又可以分為global和session關鍵字,表明該引數的修改是基於當前會話還是真格例項的生命週期。有些動態引數只能在會話中進行修改,如autocommit;有些引數修改完後,在整個例項生命週期中都會生效,如binlog_cache_size;而有些引數既可以在會話又可以在整個例項的生命週期內生效,如read_buffer_size。

3.2、日誌檔案

3.2.1、錯誤日誌

  錯誤日誌對Mysql的啟動、執行、關閉過程進行了記錄。出現Mysql不能正常啟動時,第一個必須查詢的檔案應該就是錯誤日誌檔案。使用show variables like ‘log_error’來定位檔案。

3.2.2、慢查詢日誌

  慢查詢能為SQL語句的優化帶來很好的幫助。設定一個閥值,將執行時間超過該值的所有SQL語句都記錄到慢查詢日誌檔案中。用引數long_query_time來設定。另一個引數log_queries_not_using_indexes,若執行的SQL語句沒有使用索引,則這條SQL語句會被記錄下來。

3.2.3、查詢日誌

  查詢日誌記錄了所有對Mysql請求的資訊,不論這些請求是否得到正確的執行。預設檔名為:主機名.log。

3.2.4、二進位制日誌

  二進位制記錄了對資料庫執行更改的所有操作,但是不包括SELECT和SHOW操作,還包括了執行時間和更改操作時間。可用來恢復某些資料,同時也可以用來複制同步遠端資料庫。將binlog_format設定成row,可以支援事務隔離級別為READ COMMITTED,以獲得更好的併發性。在使用MIXED格式下,mysql採用STATEMENT格式進行二進位制日誌檔案的記錄,但是有一些情況下會使用ROW格式,可能的情況如下:

1、表的儲存引擎為NDB,這個時候DML操作都會以ROW格式記錄。

2、使用了uuid()、user(),current_user(),found_rows(),row_count(),等不確定函式。

3、使用了insert delay語句

4、使用了使用者定於的函式(UDF)

5、使用了臨時表(temporary table)

注意:針對系統庫mysql裡面的表發生變化的處理規則如下:

1、 如果採用insert,update,delete直接操作表,則日誌根據binlog_format設定的格式記錄。

2、 如果使用grant,revoke,set password等DCL語句,那麼無論如何都會使用SBR模式記錄。

3、 blockhole引擎不支援row格式,ndb引擎不支援statement格式。

3.3、套件字檔案

Unix系統下本地連線Mysql可以採用Unix套接字方法,需要一個套接字檔案,可以使用show variableslike ‘socket’查詢。

3.4、pid檔案和表結構定義檔案

     pid檔案是例項啟動是記錄自己程序ID號的檔案,表結構定義檔案是以frm為字尾名的檔案,還可以用來存放檢視的定義。

3.5、innodb引擎檔案

3.5.1、表空間檔案

     預設表空間檔案為ibdata1檔案innodb_data_file_path儲存資料,innodb_file_per_table可以按表分別產生一個表空間.db檔案,但僅存該表的資料索引和插入緩衝等資訊,其他資訊如undo資訊,系統事務資訊,double write buffer等還是存放在預設表空間(ibdata1或表空間組)裡。

3.5.2、重做日誌檔案

  redo log是在例項或者介質失敗的時候,用來保證資料完整性。每個innodb儲存引擎至少有一個重做日誌組,每個重做日誌檔案組下至少又2個重做日誌檔案,如預設的ib_logfile0、ib_logfile1.為了得到更高的可靠性,你可以設定多個重做映象日誌組。

  因為重做日誌條目先被寫到日誌緩衝中,然後根據一定條件重新整理到磁碟重做日誌檔案中。與redo log相關的就是innodb_flush_log_at_trx_commit的值,對innodb的效能影響很大。他有0,1,2三個值,0代表提交事務時,並不同步寫redo log,而是等master threas每秒寫。1代表commit的時候就將redo log快取寫入磁碟,2代表commit的時候將redo log快取非同步的寫入磁碟。