Mysql筆記系列一MySQL體系結構和InnoDB儲存引擎
名詞解釋:
“資料庫”和”資料庫例項”
資料庫:更側重於指的是儲存在物理磁碟上的檔案的集合,例如frm,myd,myi,ibd結尾的檔案。
資料庫例項:執行在記憶體中,正在執行的一個程序,用來操作資料庫檔案。
可以通過理解程序和程式之間的關係來類比的理解,程序就是動態的執行在記憶體中的程式,它的實體就是儲存在磁碟上的檔案,而程式則指的是靜態的,即使用特定的語言編寫的課編譯的檔案,側重的是檔案。例項就是資料庫程序,可以對資料庫進行操作的集合,資料庫就是在例項上操作在磁碟上的對映,最終的改變通過檔案的方式儲存在磁碟上。對應關係:在非叢集情況下,一個數據庫對應一個數據庫例項,在叢集情況下,一個數據庫可被多個例項使用。
啟動資料庫例項
MYSQL資料庫會去讀取配置檔案,根據配置檔案的屬性值來啟動資料庫例項,MYSQL資料庫例項啟動時,照/etc/my.cnf->/etc/mysql/my.cnf->/usr/local/mysql/etc/my.cnf->~/.my.cnf的順序讀取配置檔案,如果屬性相同,則按照最後一個配置檔案的屬性值為準,如果沒有配置檔案,則MYSQL會按照編譯時的預設引數設定啟動例項。Oracle中,如果沒有引數檔案,則啟動時會提示找不到該引數檔案,啟動失敗。
Window平臺,配置檔案的字尾以.cnf,.ini.Linux環境下,配置檔案一般放在/etc/my.cnf下。配置檔案中有一個datadir引數,該引數制定了資料庫所在的路徑,Linux下,datadir預設為/usr/local/mysql/data。
儲存引擎
資料庫的核心是儲存引擎,儲存引擎是一個抽象的概念,可以理解成一個程式,用來定義如何進行儲存的程式,資料庫有多種儲存引擎,每種儲存引擎都針對不同的情況,各有千秋。Mysql是開源的,可以根據Mysql預定義的儲存引擎介面編寫自己的儲存引擎,也可以修改原始碼,實現更多的特性。儲存引擎可分為Mysql官方儲存引擎和第三方儲存引擎。
⑴InnoDB儲存引擎
面向線上事務處理(OLTP),特點是行鎖設計,支援事務,外來鍵,非鎖定讀(即預設情況下讀取操作不會產生鎖)。MVCC(多版本併發控制)獲取高併發性,還有:二次寫,插入緩衝,自適應雜湊索引,預讀等高效能和高可用的功能。對於表的儲存,InnoDB儲存引擎採用聚集的方式,每張表的儲存按照主鍵的順序存放,如果沒有顯式的在表定義時指定主鍵,InnoDB儲存引擎會為每一行生成一個6位元組的ROWID,並以此作為主鍵。
⑵MyISAM儲存引擎
表鎖,全域性索引,不支援事務,MyISAM儲存引擎由MYD和MYI組成,MYD用來存放資料檔案,MYI用來存放索引檔案。
⑶NDB儲存引擎
叢集儲存引擎,資料全放在記憶體中,主鍵查詢速度極快。
⑷Memory儲存引擎
將表中的資料存放在記憶體中,如果資料庫重啟,崩潰,則表中資料消失,預設使用雜湊索引。
等等等,可通過在mysql中使用 show engines;查詢mysql支援的儲存引擎。
資料庫的連線方式
資料庫的連線就是連線程序和MySQL資料庫例項(即mysql server)進行通訊,即程序通訊,程序通訊的方式有以下幾個:
⑴TCP/IP
TCP/IP協議是一個網路連線協議,用來使網路上的兩個主機建立安全可靠的連線,因此,可以在TCP/IP連線上建立一個基於網路的連線請求,一般情況下,客戶端和服務端不在一個主機上,但是因為他是基於網路的,所以即使在一個主機上,也可以。
C:\Users\liumin>mysql -u root -p
⑵Unix套接字
Unix套接字不是一個協議,所以只能在Mysql客戶端和資料庫例項在同一臺伺服器的情況下使用,可以在配置檔案中指定套接字檔案的路徑,eg:-socket=/tmp/mysql.sock。當資料庫例項啟動後,可以通過mysql -u username -S pathofsocket來進行連線。
C:\Users\liumin>mysql -u root -S /tmp/mysql.sock
還有命名管道和共享記憶體,但是現在常用的連線方式是建立在TCP/IP協議上的資料庫連線。
InnoDB儲存引擎
InnoDB有Innobase Oy公司開發,是一個支援事務,行鎖,外來鍵,MVCC(多版本併發控制)提供非鎖定讀(即在讀取操作中不適用鎖),還有插入快取,二次寫,自適應性雜湊等特性。
InnoDB的體系架構
首先儲存引擎是一個程式,程式自然有很多分工和與之對應的執行緒,因此在記憶體中,系統會為儲存引擎分配一個記憶體區域(記憶體池)。記憶體池中有多個後臺執行緒,後臺執行緒的主要任務是負責重新整理記憶體池中的資料,保證緩衝池中的記憶體緩衝的是最近的資料。
後臺執行緒:
可以通過 show engine innodb status\G;命令來檢視innodb儲存引擎的狀態:(內容有所刪減,我只保留我們目前需要關注的內容)
mysql> show engine innodb status\G;
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
...
--------
FILE I/O
--------
I/O thread 0 state: wait Windows aio (insert buffer thread)
I/O thread 1 state: wait Windows aio (log thread)
I/O thread 2 state: wait Windows aio (read thread)
I/O thread 3 state: wait Windows aio (read thread)
I/O thread 4 state: wait Windows aio (read thread)
I/O thread 5 state: wait Windows aio (read thread)
I/O thread 6 state: wait Windows aio (write thread)
I/O thread 7 state: wait Windows aio (write thread)
I/O thread 8 state: wait Windows aio (write thread)
I/O thread 9 state: wait Windows aio (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
1139 OS file reads, 447714 OS file writes, 21607 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
...
預設情況,InnoDB儲存引擎的後臺執行緒有7個,4個I/O thrads(insert buffer thread,log thread,read thread,write thread),1個master thread,1個lock thread,1個錯誤監控 thread.
記憶體劃分:
InnoDB的記憶體由以下幾個部分組成:緩衝池,日誌緩衝池,額外的記憶體池。可以通過配置檔案中的引數innodb_buffer_pool_size和innodb_log_buffer_size的大小配置。
通過 show engine innodb status\G;可以看到緩衝池的狀態。
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137363456
Dictionary memory allocated 436363
Buffer pool size 8192
Free buffers 4012
Database pages 4165
Old database pages 1517
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 3, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 1114, created 3051, written 5858
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 4165, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
buffer pool size 表示緩衝幀的數量,每個幀16K,即換算下來為:128M,Free buffers 為當前空閒的緩衝幀,Database pages表示已經使用的緩衝幀,Modified db page表示髒頁的數量。
也可以通過 show variables like 'innodb_buffer_pool_size'\G;來檢視特定區域的配置情況,其他的同理。
mysql> show variables like 'innodb_buffer_pool_size'\G;
*************************** 1. row ***************************
Variable_name: innodb_buffer_pool_size
Value: 134217728
1 row in set, 1 warning (0.00 sec)
⑴緩衝池
緩衝池是佔用記憶體最大的一部分,用來存放各種資料的快取。InnoDB的儲存引擎的工作方式是將資料庫檔案按照頁(每頁16k)讀取到緩衝池,然後按最近最少使用的演算法來保留住緩衝池中的緩衝資料,資料庫的修改也是最先在緩衝池中的頁,然後按照一定的頻率將緩衝池中的髒頁重新整理到檔案。緩衝池的資料型別有:索引頁,資料頁,undo頁,插入緩衝,自適應雜湊索引,InnoDB儲存的鎖資訊,資料字典等。
⑵日誌緩衝
日誌緩衝即先將日誌資訊放入這個區域,然後按照一定的頻率重新整理到重做日誌檔案。頻率不需要設定太大,因為一般情況下每一秒中就會重做日誌緩衝重新整理。
⑶額外記憶體池
對於一些資料結構的記憶體分配問題,需要從額外的記憶體池中申請,當該區域的記憶體不足時,會從緩衝池中申請。
關鍵特性:
⑴插入緩衝
插入緩衝,和資料頁一樣,是物理頁的一個組成部分。應用程式中行記錄的插入順序是按照主鍵遞增的順序進行插入的,則插入聚集索引(資料庫錶行中資料的物理順序與鍵值的邏輯順序相同。一個表只能有一個聚集索引)一般是順序的,不需要磁碟的隨機讀取,即當執行插入操作時,主鍵列會自動增長,頁中的行記錄按照主鍵行順序存放,一般情況下,不需要隨機讀取另一個頁執行記錄的存放,因此,插入操作能迅速完成。但是普遍情況下,一張表有多個非聚集的輔助索引,這個時候進行插入操作時,資料的存放還是按照主鍵的執行順序存放,但是對於非聚集索引,葉子節點的插入不再是順序的。
InnoDB為了解決這個問題,設計了插入快取,對於非聚集索引的插入或更新操作,不是每一次直接插入索引頁中,而是先判斷插入的非聚集索引頁是否在緩衝池中,如果在直接插入,如果不在,先放入一個插入緩衝區中,然後按照一定的頻率執行插入快取和非聚集碎銀頁子節點的合併操作,這時通常能夠將多個插入合併到一個操作中,大大提高非聚集索引的插入效能。但是插入緩衝的使用需要兩個條件:1.索引是輔助索引2.索引不是唯一。
⑵兩次寫
當資料庫發生宕機時,可能發生資料庫正在寫一個頁面,但這個頁面有隻寫了一部分,我們稱為部分寫失效,又由於這個時候頁本身已經損壞,所以進行重做日誌記錄是不行的,因為重做日誌記錄是對頁的物理操作。因此設計了兩次寫,即在應用重做日誌前,我們需要一個頁的副本,當寫入失效的時,先通過頁的副本來還原該頁,在進行重做。
doublewrite由兩部分組成:
一是記憶體中的doublewrite buffer,大小為2MB,另一部分是物理磁碟上共享表空間中連續的128個頁,即兩個區,大小同樣是2MB,當緩衝池的髒頁重新整理時,即進行修改操作時,並不直接寫到磁碟,而是通過memcpy函式將髒頁先拷貝到記憶體中的doublewrite buffer,之後 通過doublewrite bufffer分兩次,每次寫入1MB到共享表空間的物理磁碟上,然後呼叫fsync函式,同步到磁碟,因為doublewrite頁是連續的,所以這個過程也是順序寫的,並不會造成很多資源的使用,在完成doublewrite頁的寫入後,再將doublewrite buffer的頁寫入各個表中間檔案中,此時的寫入則是離散的。
如果系統在將頁寫入磁碟的過程中崩潰了,則在恢復過程中,InnoDB儲存引擎可以從共享表空間中的doublewrite中找到該頁的一個副本,然後將其拷貝到表空間檔案,在重用重做日誌。
⑶自適應雜湊
雜湊的查詢時間複雜度為O(1),InnoDB儲存引擎會監控對錶上索引的查詢,如果觀察到建立雜湊索引可以帶來速度的提升,則建立雜湊索引,稱為自適應,自適應雜湊通過B+樹構造,因此建立的速度很快,而且不需要將整個表都建雜湊索引,InnoDB儲存引擎會根據訪問的頻率和模式來為某些頁建立雜湊索引。
啟動,關閉和恢復
InnoDB儲存引擎的啟動,關閉指的是在MYSQL例項的啟動過程中對InnoDB表儲存的處理過程,在關閉的時候,引數innodb_fast_shutdonw影響著儲存引擎為InnoDB的行為,引數取值為0,1,2。0代表Mysql關閉時,需要完成所有的full purge和merge insert buffer操作。1是預設值,表示不需要上述操作,但是在緩衝池中的資料髒頁還是要重新整理到磁碟上。2表示不完成full purge 和merge into buffer操作,也不將緩衝池的資料髒頁寫回到磁碟,而是將日誌都寫入日誌檔案,這樣不會又任何事務的丟失,但Mysql資料庫下次啟動時,會執行恢復操作。
參考《MySQL技術內幕 InnoDB儲存引擎》 姜承堯著