讀書筆記之MySQL技術內幕

前言

本文內容基本摘抄自《MySQL技術內幕 InnoDB存儲引擎》,以供複習之用,沒有多少參考價值。想要更詳細瞭解請參考原書。前端

第一章.MySQL體系結構和存儲引擎

數據庫是物理操做系統文件或其餘形式文件類型的集合。MySQL數據庫實例由後臺線程以及一個共享內存區組成。MySQL是一個單進程多線程的架構的數據庫算法

MySQL數據庫區別於其餘數據庫的特色是插件式的表存儲引擎:sql

InnoDB存儲引擎:支持事務,主要面向在線事務處理的應用。特色是行鎖設計、支持外鍵,並支持相似於Oracle的非鎖定讀,即默認讀取操做不會產生鎖。InnoDB經過使用多版本併發控制(MVCC)來得到高併發性,而且實現SQL標準的4種隔離級別,默認REPEATABLE。同時,使用next-key locking策略來避免幻讀的產生。除此以外,InnoDB還提供了插入緩衝、二次寫、自適應哈希索引、預讀等功能。數據庫

MyISAM存儲引擎:不支持事務、表鎖設計,支持全文索引,主要面向在線分析處理的應用。MyISAM存儲引擎的另外一個不同凡響的地方是它的緩衝池只緩存索引文件,而不緩衝數據文件,自己不支持外鍵,對於外鍵的定義只是起到註釋的做用。數組

鏈接MySQL的幾種方式:TCP/IP、命名管道和共享內存、UNIX域套接字。緩存

第二章.InnoDB存儲引擎

InnoDB體系架構

後臺線程:1.Master Thread主要負責將緩衝池中的數據異步刷新到磁盤,保證數據的一致性,包括髒頁的刷新、合併插入緩衝、UNDO頁的回收等;2.InnoDB大量使用AIO來處理寫IO請求,IO Thread的工做複製這些IO請求的回調處理;3.事務被提交後,所使用的undolog可能再也不須要,所以須要Purge Thread來回收已經使用並分配的undo頁;4.Page Cleaner Thread做用是將以前版本中髒頁的刷新操做都放入到單獨的線程中來完成,目的是爲了減輕原Master Thread的工做及對於用戶查詢線程的阻塞。數據結構

圖片描述
內存:1.緩衝池簡單來講就是一塊內存區域,經過內存的速度來彌補磁盤速度較慢對數據庫性能的影響(頁從緩衝池刷新回磁盤的操做並非在每次頁發生更新時觸發,而是採用Checkpoint機制),從1.0版本開始容許多個緩衝池實例;2.InnoDB存儲引擎首先將重作日誌信息放入重作日誌緩衝這個緩衝區,而後按必定頻率將其刷新到重作日誌文件;3.在對一些數據結構自己的內存進行分配時,須要從額外的內存池中進行申請,當該區域內存不夠時,會從緩衝池中進行申請。多線程

一般來講,數據庫中的緩衝池是經過LRU算法進行管理。最頻繁使用的頁在前端,最少使用的頁在尾端。InnoDB對傳統的LRU算法作了一些優化,LRU列表中添加了midpoint位置。新讀取到的頁,雖然是最新訪問的頁,但不是直接放入到LRU列表的首部,而是放入到LRU列表的midpoint位置。能夠設定頁讀取到mid位置後須要等待多久纔會加入到LRU列表的熱端。這樣作是避免相似索引或數據的掃描操做會使緩衝池中的頁被刷新出,從而影響緩衝池的效率。架構

Checkpoint技術

爲避免數據丟失問題,當前事務數據庫系統廣泛採用了Write Ahead Log策略,即當事務提交時,先寫重作日誌,再修改頁。Checkpoint解決下面問題:縮短數據庫恢復時間、緩衝池不夠用時,將髒頁刷新到磁盤;重作日誌不可用時,刷新髒頁。併發

當數據庫發生宕機時,數據庫不須要重作全部的日誌,由於Checkpoint以前的頁都已經刷新回磁盤;當緩衝池不夠用,根據LRU算法會溢出最近最少使用的頁,若此頁爲髒頁,須要強制執行Checkpoint,將髒頁刷回磁盤;重作日誌是循環使用而不是無限增大的,當被重用的部分仍須要使用時,必須強制產生Checkpoint,將緩衝池中的頁至少刷新到當前重作日誌的位置。

Master Thread

Master Thread具備最高的線程優先級別。內部由多個循環組成:主循環、後臺循環、刷新循環、暫停循環。

Loop分爲每秒操做和每10秒操做,每秒操做包括:日誌緩衝刷新到磁盤,即便這個事務尚未提交(老是);合併插入操做(可能);至多刷新100個InnoDB的緩衝池中的髒頁到磁盤(可能);若是當前沒有用戶活動,則切換到background loop(可能)。每10秒操做包括:刷新100個髒頁到磁盤(可能的狀況下);合併至多5個插入緩衝(老是);將日誌緩衝刷新到磁盤(老是);刪除無用的Undo頁(老是);刷新100個或者10個髒頁到磁盤。

若當前沒有用戶活動或者數據庫關閉,就會切換到這個循環。background loop會執行:刪除無用的undo頁(老是);合併20個插入緩衝(老是);跳回到主循環(老是);不斷刷新100個頁直到符合條件(可能,跳轉到flush loop中完成)。

若flush loop無事可作,會切換到suspend loop,將Master Thread掛起,等待事件的發生。

InnoDB關鍵特性

Insert Buffer:

彙集索引是指該索引中鍵值的邏輯順序決定了表中相應行的物理順序;而非彙集索引索引的邏輯順序與行的物理存儲順序無關。主鍵是一種特殊的具備惟一約束的索引,能夠是彙集索引或是非彙集索引。

InnoDB設計了Insert Buffer,對於非彙集索引的插入或更新操做,不是每一次直接插入到索引頁中,而是先判斷插入的非彙集索引頁是否在緩衝池中存在,是的話直接插入,不然先放到一個Insert Buffer對象中,而後再以必定的頻率和狀況進行Insert Buffer和輔助索引頁子節點的merge操做,這時一般能將多個插入合併到一個操做中。

Insert Buffer的使用須要同時知足兩個條件:索引是輔助索引和索引非惟一。插入彙集索引通常是順序的,不須要磁盤的隨機讀取,而非惟一是由於若是索引惟一,每次插入時還要去離散查找頁來肯定惟一性,從而致使Insert Buffer失去意義。

Change Buffer時Insert Buffer的升級,InnoDB能夠對DML都進行緩衝。

Insert Buffer的數據結構時一棵B+樹。非葉節點存放查詢的search key。當一個輔助索引要插入到頁(space,offset)時,若是這個頁不在緩衝池中,那麼InnoDB存儲引擎首先根據上述規則構造一個search key,接下來查詢Insert Buffer這棵B+樹,而後再將這條記錄插入到Insert Buffer B+樹的葉子節點。同非葉節點同樣,葉子節點也須要先構造,再插入。

Merge Insert Buffer的操做發生在如下狀況:輔助索引頁被讀取到緩衝池時;Insert Buffer Bitmap頁追蹤到該輔助索引頁無可用空間;Master Thread。

兩次寫:

Insert Buffer帶來性能上的提高,double write帶來數據頁的可靠性。double write分兩部分,一部分是內存中的doublewrite buffer,另外一部分是物理磁盤上共享表空間的doublewrite。在對緩衝池的髒頁進行刷新時,並不直接寫磁盤,而是會經過memcpy函數將髒頁先複製到內存中的doublewrite buffer,以後經過doublewrite buffer兩次順序寫入到doublewrite,而後調用fsync函數同步磁盤。若是操做系統在將頁寫入到磁盤時發生了崩潰,恢復時先從共享表空間找到副本複製到表空間文件再應用重作日誌。

自適應哈希索引:

InnoDB存儲引擎會監控對錶上各索引頁的查詢。若是觀察到創建哈希索引能夠帶來速度提高,則創建哈希索引。
AHI經過緩衝池的B+樹索引頁構造,創建速度快,且無需對整張表創建哈希索引。

異步IO:

異步IO在發送完IO請求後能夠繼續發出新的IO請求,等待通知便可,不用等待請求結果;且AIO能夠進行IO Merge。

刷新鄰接頁:

當刷新一個髒頁時,InnoDB會檢測該頁所在區的全部頁,若是是髒頁,那麼一塊兒進行刷新。這樣能夠利用AIO合併多個IO操做。

第三章.文件

參數文件(my.cnf):當MySQL實例啓動時,數據庫會先去讀一個配置參數文件,用來尋找數據庫的各類文件所在位置以及指定某些初始化參數,這些參數一般定義了某種內存結構有多大。
日誌文件:錯誤日誌、慢查詢日誌、查詢日誌、二進制日誌。二進制日誌記錄了對MySQL數據庫執行更改的全部操做,不包括select、show這類。二進制日誌有幾種做用:某些數據的恢復須要二進制日誌;複製;經過二進制日誌信息進行審計,判斷是否有對數據庫進行注入的攻擊。
套接字文件:在UNIX系統下本地鏈接MySQL能夠採用UNIX域套接字方式,須要一個套接字文件。
pid文件:MySQL實例啓動時,會將本身的進程ID寫入pid文件。
表結構定義文件:MySQL數據的存儲是根據表進行的,每一個表都有與之對應的文件,不論採用何種存儲引擎,都有一個後綴frm的文件記錄了該表的表結構定義。
InnoDB存儲引擎文件:默認配置下,表的數據存放在默認表空間文件ibdata1中。能夠設置爲每一個表設計獨立表空間存放數據,但仍有相關信息須要存放在共享表空間。每一個InnoDB存儲引擎至少有一個重作日誌文件組,每一個組至少有兩個重作日誌文件,ib_logfile0和ib_logfile1,以循環寫入方式運行。

第四章.表

索引組織表:InnoDB存儲引擎中,表都是根據主鍵順序組織存放的,稱爲索引組織表。若是建立表時沒有顯式定義主鍵,InnoDB會首先判斷表中是否有非空惟一索引,存在則以第一個定義的非空惟一索引爲主鍵,不存在則InnoDB自動建立6字節大小的指針rowid。

表空間:從InnoDB存儲引擎的邏輯存儲結構來看,全部數據都被邏輯地存放在一個空間中,稱爲表空間。表空間又由段(segment)、區(extent)、頁(page)組成。段分爲數據段、索引段、回滾段等。數據段即爲B+樹的葉子節點、索引段即爲B+樹的非索引節點。區是由連續頁組成的空間,每一個區大小1MB。頁是InnoDB磁盤管理的最小單位,有數據頁、undo頁、系統頁、事務數據頁等。InnoDB存儲引擎是面向列的,也就是說數據是按行進行存放的。

InnoDB行記錄格式:

  • Compact行記錄格式圖片描述
  • Redundant行記錄格式

圖片描述

InnoDB存儲引擎能夠將一條記錄中的某些數據存儲在真正的數據頁面以外。若是能夠在一個頁中至少放入兩行數據,那varchar(TEXT或BLOB)類型的行數據就不會存放到BLOB頁中去。

InnoDB數據頁格式:數據頁由文件頭、頁頭、Infimun和Supremum Records、User Records、Free Space、Page Directory、File Trailer組成。

約束:數據庫提供約束機制來保證數據庫中數據的完整性:實體完整性、域完整性、參照完整性。InnoDB提供以下約束:Primary Key、Unique Key、Foreign Key、Default、Not Null。約束是一個邏輯的概念,用來保證數據的完整性,而索引是一個數據結構,既有邏輯上的概念,還表明着物理存儲的方式。

Mysql不支持傳統Check約束,可是經過Enum和Set類型能夠解決部分需求,對於連續值的範圍約束或更復雜的約束,則須要經過觸發器。觸發器的做用是在執行Insert、Delete、Update命令before或after自動調用SQL命令或存儲過程。InnoDB在外鍵創建時會自動地對該列添加一個索引Key。

視圖:Mysql中視圖是一個命名的虛表,由一個SQL查詢來定義,能夠看成表使用。與持久表不一樣,視圖中的數據沒有實際的物理存儲。

分區表:分區的過程是將一個表或索引分解爲多個更小、更可管理的部分。MySQL數據庫支持水平分區,並不支持垂直分區。Mysql數據庫的分區是局部分區索引,一個分區中既存放了數據又存放了索引。而全局分區是指,數據存放在各個分區中,可是全部數據的索引存放在一個對象中。目前Mysql支持:RANGE分區、List分區、Hash分區、key分區、Columns分區。子分區容許在分區的基礎上再進行分區,也稱符合分區。Mysql容許在RANGE和LIST的分區上再進行Hash或Key的子分區。

對於OLAP的應用,分區的確能夠很好提升查詢性能,由於OLAP應用大多數查詢須要頻繁掃描一張大表。OLTP則不必定,若根據主鍵分區,那麼進行主鍵查詢或許有幫助,但對於別的列索引查詢反而會下降性能。

第五章.索引和算法

InnoDB存儲引擎支持如下幾種常見索引:B+樹索引、全文索引、哈希索引。自適應哈希索引會根據表的使用狀況自動生成,不能人爲干預。B+樹索引找到被查找數據行所在的頁,而後數據庫把頁讀入內存,再在內存中進行查找,獲得查找的數據。
B+樹索引經過高扇出性保證高度通常在2~4層。B+樹索引分爲彙集索引和輔助索引,彙集索引和輔助索引不一樣的是,葉子節點存放的是不是一整行的信息。

彙集索引就是按照每張表的主鍵構造一棵B+樹,同時葉子節點存放的即爲整張表的行記錄數據,彙集索引的葉子節點稱爲數據頁。每一個數據頁經過一個雙向鏈表來進行鏈接。經過查看錶空間文件發現非數據頁節點存放的僅僅是鍵值及指向數據頁的偏移量,而不是一個完整的行記錄,而數據頁上存放的是完整的每行的記錄。彙集索引的存儲其實並非物理上連續的,而僅僅邏輯上連續。頁之間經過雙向鏈表進行維護,每一個頁中的記錄之間也經過雙向鏈表維護。彙集索引還有一個優勢是它對於主鍵的排序查找和範圍查找速度很是快。

輔助索引也是B+樹,葉子節點並不包含行記錄的所有數據。葉子節點除了包含鍵值外,每一個葉子節點中的索引行中還包含了一個書籤,因爲InnoDB是索引組織表,所以InnoDB存儲引擎的輔助索引的書籤就是相應行數據的彙集索引鍵。

索引的建立和刪除有兩種方法,一種是alter table add/drop key,另外一種是create/drop index。

並非全部的查詢條件中出現的列都須要添加索引。對於何時添加B+樹索引,經驗是具備高選擇性的列纔有必要添加索引,經過show index from tablename 能夠查看cardinality值來查看列是否具備高選擇性。

聯合索引是指對錶上的多個列進行索引。聯合索引也是一棵B+樹,不一樣的是聯合索引的鍵值數量大於等於2.聯合索引已經對後面的鍵值進行了排序處理。

InnoDB存儲引擎支持索引覆蓋,即從輔助索引中就能夠獲得查詢的記錄,而不須要查詢彙集索引中的記錄。使用覆蓋索引的一個好處是輔助索引不包含整行記錄的全部信息,能夠減小IO操做。

InnoDB存儲引擎使用哈希算法來對字典進行查找,其衝突機制採用鏈表方式哈希函數採用除法散列方式。自適應哈希索引基於此實現,對於字典類型的查找很是迅速,可是對於範圍查找無能爲力。

全文檢索經過使用倒排索引來實現。倒排索引在輔助表中存儲了單詞與單詞自身在一個或多個文檔中所在位置之間的映射,一般使用關聯數組實現。

第六章.鎖

InnoDB存儲引擎提供一致性的非鎖定讀、行級鎖支持。行級鎖沒有相關額外的開銷,並能夠同時的到併發性和一致性。

數據庫中有兩種鎖:lock和latch。latch鎖定時間短,目的是保證併發線程操做臨界資源的正確性,沒有死鎖檢測機制,分爲互斥量和讀寫鎖。lock的對象是事務,用來鎖定數據庫中的對象,如表、頁、行。而且通常lock的對象僅在事務commit或rollback後進行釋放,lock有死鎖機制。

InnoDB存儲引擎實現了以下兩種標準的行級鎖,容許事務讀一行數據的共享鎖(S鎖)和容許事務刪除或更新一行數據的排他鎖(X鎖)。InnoDB支持意向鎖爲表級別的鎖,意向共享鎖和意向排他鎖。

一致性的非鎖定讀是指InnoDB存儲引擎經過行多版本控制的方法來讀取當前執行時間數據庫中行的數據。若是讀取的行正在執行delete或update操做,這時讀取操做不會所以去等待行上鎖的釋放。相反,InnoDB會去讀取行的快照數據。快照數據是指該行的以前版本的數據,這是經過undo段來完成。undo段是用來在事務中回滾數據,所以快照數據自己沒有開銷。且快照數據無需上鎖。不一樣事務隔離級別不都是採用非鎖定的一致性讀,即便採用非鎖定一致讀,對於快照數據的定義也各不相同。

某些狀況下,須要顯示地對數據庫讀取操做進行加鎖以保證數據邏輯的一致性。InnoDB對於select提供兩種一致性鎖定讀操做:

  • select...for update(對讀取行加一個X鎖)
  • select...lock in share mode(對讀取行記錄加上一個S鎖)

InnoDB存儲引擎有3種行鎖的算法:

  • Record Lock:單個行記錄上的鎖
  • Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄自己
  • Next-Key Lock:Gap+Record,鎖定一個範圍,而且鎖定記錄自己

InnoDB存儲引擎默認事務隔離級別是Repeatable read,該隔離級別下,其採用next-key locking加鎖。而在Read committed下,其僅採用Record Lock。當查詢的索引含有惟一屬性時,InnoDB存儲引擎會對Next-Key
Lock進行優化,將其降級爲Record Lock。Next-key Lock用來解決幻讀問題,組織多個事務將記錄插入到同一個範圍。

髒讀是指一個事務能夠讀到另一個事務中未提交的數據;不可重複讀是指在一個事物內屢次讀取到同一個數據集合,但因爲另外一事務的修改,第一個事務兩次讀到的數據不同。丟失更新是指一個事務的更新操做會被另外一個事務的更新操做所覆蓋,從而致使數據不一致,避免的話須要讓事務串行化,相似整個事務階段都加鎖。

死鎖是指兩個或以上的事務在執行過程當中,因爭奪鎖資源而形成的一種互相等待的現象。最簡單的辦法是超時機制,但超時機制根據FIFO的順序選擇回滾對象,若超時事務所佔權重較大,效率就會低。因此也會經過等待圖來進行死鎖檢測,存在死鎖時回滾undo量最小的事務。

第七章.事務

InnoDB中的事務徹底符合ACID的特性,即原子性、一致性、隔離性、持久性。從事務理論角度,能夠分爲如下幾類:扁平事務、帶有保存點的扁平事務、鏈事務、嵌套事務、分佈式事務。

事務隔離性由由鎖實現,。原子性、一致性、持久性經過數據庫的redo log和undo log來完成,redo log稱爲重作日誌,用來保證事務的原子性和持久性。undo log用來保證事務的一致性,用來幫助事務回滾及MVCC的功能。

重作日誌都是以512字節進行存儲的。這意味着重作日誌緩存、重作日誌文件都是以塊的方式進行保存,稱爲重作日誌塊。因爲重作日誌塊的大小和磁盤扇區的大小同樣,都是512字節,所以重作日誌的寫入能夠保證原子性,不須要doublewrite技術。

重作日誌記錄了事務的行爲,能夠很好地經過其對頁進行「重作」操做。可是事務有時還須要進行回滾操做,這時就須要undo。redo存放在重作日誌文件中,undo存放在數據庫內部的一個特殊段中,稱爲undo段。undo段位於共享表空間中。undo只是邏輯地將數據庫恢復,好比用insert恢復delete,而不是把頁回滾爲事務開始的樣子,由於可能別的事務對同一個頁進行修改。undo的另外一個做用是MVCC。undo的產生會伴隨着redo log的產生,由於undo log也須要持久性的保護。

purge用於最終完成delete和update操做。這樣設計是由於InnoDB存儲引擎支持MVCC,因此記錄不能在事務提交時當即進行處理,這時其餘事務可能正在引用這行,故InnoDB存儲引擎須要保存記錄以前的版本。而是否能夠刪除該條記錄經過purge來判斷。若該行記錄不被任何其餘事務引用,那麼能夠進行真正的delete操做。

InnoDB存儲引擎提供了對XA事務的支持,並經過XA事務來支持不一樣數據庫之間分佈式事務的實現。使用分佈式事務隔離級別必須設置爲Serializable,全局事務要求在其中的全部參與的事務要麼都提交,要麼都回滾。XA事務由一個或多個資源管理器、一個事務管理器以及一個應用程序組成。

相關文章
相關標籤/搜索