《MySQL技術內幕 InnoDB存儲引擎 》學習筆記

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

1.3 MySQL存儲引擎

  數據庫和文件系統最大的區別在於:數據庫是支持事務的算法

InnoDB存儲引擎:sql

  MySQL5.5.8以後默認的存儲引擎,主要面向OLTP(聯機事務處理,面向基本的、平常的事務處理)數據庫

  支持事務,支持外鍵、支持行鎖(有的狀況下也會鎖住整個表)、非鎖定讀(默認讀取操做不會產生鎖)緩存

  經過使用MVCC來獲取高併發性,而且實現sql標準的4種隔離級別,默認爲可重複讀級別數據結構

  使用一種被稱成next-key locking的策略來避免幻讀(phantom)現象併發

  還提供了插入緩存(insert buffer)、二次寫(double write)、自適應哈希索引(adaptive hash index)、預讀(read ahead)等高性能技術。分佈式

  表數據採用彙集方式,每張表的存儲都按主鍵的順序進行存放。高併發

 

MyISAM存儲引擎:性能

  不支持事務、支持全文索引,表鎖設計,主要面向一些OLAP(聯機分析處理,數據倉庫的主要應用)。spa

  它的緩衝池只緩衝索引文件,而不緩衝數據文件.

  該存儲引擎表由MYD和MYI組成,MYD用來存放數據文件,MYI用來存放索引文件.

 

NDB:

  是一個集羣存儲引擎,其特色是數據所有放在內存中。

  所以主鍵查找速度極快,並經過添加NDB數據庫存儲節點能夠線性提升數據庫性能,是高可用,高性能的集羣系統。

 

Memory:

  將表中的數據存放在內存中,若是數據庫重啓或發生崩潰,表中的數據都將消失。

  它很是適合存儲臨時數據的臨時表.默認採用哈希索引。

  只支持表鎖,併發性較差。

 

第5章  索引與算法

5.1 InnoDB存儲引擎索引概述

  Innodb存儲引擎支持如下幾種常見的索引:

    B+樹索引

    全文索引

    哈希索引

  自適應哈希索引特性:InnoDB存儲引擎會根據表的使用狀況自動爲表生成哈希索引,不能人爲干預是否在表中生成哈希索引。

  B+樹索引並不能找到一個給定鍵值的具體行。B+樹索引能找到的只是被查找數據行所在的頁。而後數據庫經過把頁讀入到內存,再在內存中進行查找,最後獲得要查找的數據。

 

5.3 B+樹

  爲磁盤或其餘存取輔助設備設計的一種平衡查找樹。

  全部記錄點按大小順序存放在同一層的葉子節點上。

  各葉子節點由指針進行鏈接。

 

5.4 B+樹索引

  B+索引在數據庫中有一個特色是高扇出性

  B+樹的高度通常在2~4層,這也就是說查找某一鍵值的行記錄時最多隻須要2到4次IO。

  扇入:指直接調用該模塊的上級模塊的個數。

  扇出:是指該模塊直接調用的下級模塊的個數。

  B+樹索引能夠分爲彙集索引(clustered index)和輔助索引(secondary index),可是不論是彙集仍是輔助索引,其內部都是B+樹的,即高度平衡的,葉子節點存放着全部的數據。

  彙集索引和輔助索引不一樣的是,葉子節點存放的是不是一整行的信息。

 

彙集索引:

  彙集索引就是按照每張表的主鍵構造一棵B+樹。

  葉子節點中存放的是整張表的行記錄數據,葉子節點也成稱爲數據頁。

  索引組織表中數據也是索引的一部分。同B+樹數據結構同樣,每一個數據頁經過一個雙向鏈表來進行連接。

  彙集索引可以特別快的訪問針對範圍值的查詢。

 

  不少文檔寫着:彙集索引按照順序,物理地存儲數據。

  可是這本書上寫的是:彙集索引的存儲並非物理上連續的,而是邏輯上連續的。(我也不知道哪一個是對的)

  這其中的兩點:一是前面說過的頁經過雙向鏈表連接,頁是按照主鍵的順序排序;

  另外一點是每一個頁中的記錄也是經過雙向鏈表進行維護的,物理存儲上能夠一樣不按照主鍵存儲。

  彙集索引的另一個好處是,它對於主鍵的排序查找和範圍查找速度很是快。

 

輔助索引(非彙集索引):

  葉子節點並不包含行記錄的所有數據。

  葉子節點除了包含鍵值外,每一個葉子節點中的索引行中還包含了一個書籤(bookmark)。

  該書籤用來告訴innodb存儲引擎哪裏能夠找到與索引相對於的行數據。

  輔助索引的存在並不影響數據在彙集索引中的組織,所以每張表上能夠有多個輔助索引。

  當經過輔助索引來尋找數據時,innodb存儲引擎會遍歷輔助索引並經過頁基本的指針得到指向主鍵索引的主鍵,而後再經過主鍵索引來找到一個完整的行記錄。

 

B+樹索引的管理:

  ALTER  TABLE  表名  ADD   [ UNIQUE | FULLTEXT | SPATIAL ]   INDEX  索引名(屬性名  [ (長度) ]  [ ASC | DESC]); 

 

  CREATE INDEX index_test2 on table_test(age);

 

建立惟一性索引

  ALTER  TABLE  index14  ADD  UNIQUE  INDEX  index14_id ( course_id(100) ) ; 

 

建立全文索引

  ALTER  TABLE  index15  ADD  FULLTEXT  INDEX  index15_info ( info ) ; 

 

建立空間索引

  ALTER  TABLE  index18  ADD  SPATIAL  INDEX  index18_line( line ) ; 

 

建立多列索引

  ALTER  TABLE  index17  ADD  INDEX  index17_na( name, address ) ; 

 

  CREATE INDEX一個語句一次只能創建一個索引,ALTER TABLE能夠在一個語句創建多個,如:
        ALTER TABLE HeadOfState ADD PRIMARY KEY (ID), ADD INDEX (LastName,FirstName);


  只有ALTER TABLE 才能建立主鍵

  查看索引: SHOW INDEX FROM 表名

 

 

5.6 B+樹索引的使用

聯合索引:

  有多個索引列

  KEY idx_a_b(a,b) where a =xxx and b=xxx  以及 where a =xxx 都能使用該索引

  可是where b =xxx 沒發使用該索引,由於如圖,1,2,1,4,1,2不是有序的

 

 

索引覆蓋:

  Innodb存儲引擎支持索引覆蓋,即從輔助索引中就能夠獲得查詢的記錄,而不須要查詢彙集索引中的記錄。

  使用索引覆蓋的一個好處是輔助索引不包含整行記錄的全部信息,故其大小要遠小於彙集索引,所以能夠減小大量的IO操做。

 

全文檢索:

  是將存儲在數據庫中的整篇文章中的任意內容信息查找出來的技術

  InnoDB1.2.x從開始,支持全文檢索

 

 

第6章  鎖

6.3 InnoDB存儲引擎中的鎖

鎖的類型:

InnoDB存儲引擎實現了以下兩種標準的行級鎖:

  • 共享鎖(讀鎖 或 S LOCK),容許事務讀一行數據
  • 排它鎖(寫鎖 或 X LOCK),容許事務刪除或者更新一行數據

  當一個事務已經得到了行r的共享鎖,那麼另外的事務能夠當即得到行r的共享鎖,由於讀取並無改變行r的數據,咱們稱這種狀況爲鎖兼容。

  但若是有事務想得到行r的排它鎖,則它必須等待事務釋放行r上的共享鎖——這種狀況咱們成爲鎖不兼容。

  InnoDB存儲引擎支持多粒度鎖定,這種鎖定容許在行級上的鎖和表級上的鎖同時存在。爲了支持在不一樣粒度上進行加鎖操做,InnoDB存儲引擎支持一種額外的鎖方式,咱們稱之爲意向鎖。

  意向鎖是表級別的鎖,其設計目的主要是爲了在一個事務中揭示下一行將被請求的鎖的類型。

    • 意向共享鎖(IS Lock),事務想要得到一個表中某幾行的共享鎖。
    • 意向排它鎖(IX Lock),事務想要得到一個表中某幾行的排它鎖。 
      由於InnoDB支持的是行級別的鎖,因此意向鎖其實不會阻塞除全表掃之外的任何請求。

 

一致性的非鎖定讀操做:

  是指InnoDB存儲引擎經過行多版本併發控制(MVCC)的方式來讀取當前執行時間數據庫中行的數據。

  若是讀取的行正在執行DELETE、UPDATE操做,這時讀取操做不會所以等待行上的鎖釋放,相反,存儲引擎會去讀取一個快照數據。

快照數據是指該行以前版本的數據,該實現是經過Undo段來實現。而Undo用來在事務中回滾數據,於是快照數據自己是沒有額外的開銷。此外,讀取快照數據是沒必要要上鎖的,由於沒有必要對歷史的數據進行修改。

 

  在Read Comitted事務隔離級別下,對於快照數據,老是讀取被鎖定行的最新一份快照數據。

  在Repeatable Read事務隔離級別下,對於快照數據,老是讀取事務開始時的行數據版本。

  因此,對於Read Commited的事務隔離級別而言,其實違反了事務的隔離性。

 

鎖定讀操做:

  SELECT…FOR UPDATE 對讀取的行記錄加一個X鎖。其餘事務想在這些行上加任何鎖都會被阻塞。

  SELECT…LOCK IN SHARE MODE 對讀取的行記錄加一個S鎖。其餘事務能夠向鎖定的記錄加S鎖,可是對於加X鎖,則會被阻塞。

 

6.4 鎖的算法

行鎖的3種算法:

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

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

Record Lock老是會鎖住索引記錄,若是InnoDB存儲引擎創建的時候沒有設置任何一個索引,這時InnoDB存儲引擎會使用隱式的主鍵來進行鎖定。

好比:`SELECT * FROM t WHERE a < 6 lock in share mode,該語句會鎖定(-oo, 6)這個數值區間的全部數值。

 

解決幻讀問題:

  InnoDB存儲引擎採用Next-Key Locking機制來避免幻讀。

  幻讀:同一事務下,連續執行兩次一樣的SQL語句可能致使不一樣的結果。第二次SQL語句可能會返回以前不存在的行。

  假如表t由1,2,5三個值組成,  where a > 2 ,被鎖住的不只是5這個值,而是(2,+∞)這個範圍加了X鎖

  在讀提交級別下,僅採用Record Lock

 

6.5 鎖問題

髒讀:

  即一個事務能夠讀到另外一個事務中未提交的數據,違反了數據庫的隔離性。發生條件:READ UNCOMMITED,這個隔離級別在Mysql中不使用。

不可重複讀:

  一個事務兩次讀同一數據,結果不同。(另外一個事務修改了改數據並提交)

  不可重複讀和髒讀的區別是:髒讀是讀到未提交的數據;而不可重複讀讀到的確實是已經提交的數據,可是其違反了數據庫事務一致性的要求。

  InnoDB的默認事務隔離級別是READ REPEATABLE,採用Next-Key Lock算法,解決了不可重複讀(幻讀)問題。

  在Next-Key Lock 算法下,不只僅是鎖住掃描到的索引,並且還鎖住這些索引覆蓋的範圍(gap)。所以對於這個範圍內的插入都是不容許的。

 

6.7 死鎖

  死鎖是指兩個或兩個以上的事務在執行過程當中,因爭奪鎖資源而形成的一種相互等待的現象。

  超時機制:當一個事務等待超時,則對它進行回滾。可是有可能回滾的這個事務的時間要比另外一個事務要多。(就是還不如回滾另外一個沒超時的)

  InnoDB採用wait-for graph(等待圖)的方式來進行死鎖檢測。

 

6.7 鎖升級

  指將當前鎖的粒度下降,好比1000個行鎖升級爲一個頁鎖,或者將頁鎖升級爲表鎖。

  InnoDB不存在鎖升級的問題。

  其根據每一個事務訪問的每一個頁對鎖進行管理,採用的是位圖的方式。

  無論事務鎖住頁中的一個記錄仍是多個記錄,其開銷是同樣的。

 

 

第7章  事務

7.1 認識事務

  事務是訪問並更新數據庫的一個程序執行單元。

 

ACID:

  Atomicity 原子性: 數據庫事務是不可分割的工做單位, 要麼都作, 要麼都不作.

  Consistency 一致性: 事務不會破壞事務的完整性約束. 事務將數據庫從一個一致狀態轉變爲另外一個一致狀態

  Isolation 隔離性: 事務之間相互分離, 在提交以前相互不可見.

  Durability 持久性: 事務一旦提交, 其產生的效果就是永久的

 

分類

  • 扁平事務
  • 帶保存點的扁平事務
  • 鏈事務
  • 嵌套事務 (nested transactions)
  • 分佈式事務

扁平事務

  使用最爲頻繁

  • 以 BEGIN [WORK] / START TRANSACTION開始
    • COMMIT [WORK] 成功提交
    • ROLLBACK [WORK] 回滾

帶保存點的扁平事務

  就是能夠不會滾所有,只回滾一部分

  • 使用 SAVE WORK 新增保存點
  • 扁平事務默認帶着一個事務開始時的保存點

 

7.2 事務的實現

  事務的隔離性由鎖實現

  原子性,一致性,持久性 由 redo log / undo log 實現

  undo log 保證事務的一致性, 邏輯日誌, 根據每行記錄進行記錄,幫助事務回滾及MVCC

  redo log(重作日誌): 保證事務的原子性和持久性, 物理日誌

 

redo log:

  由兩部分組成:內存中的重作日誌緩衝,易失的

  重作日誌文件,持久的

  事務提交時,必須將事務的的全部日誌寫入重作日誌進行持久化。

 

 

undo log:

  記錄的是 SQL, undo 以後底層物理文件格式可能會改變

  當前事務經過undo讀取以前的行版本信息,來實現非鎖定讀

  undo log 會產生redo log,由於undo log也須要持久性的保護

 

purge:

  刪除並無刪除原數據,只是delete flag置爲1

  若該行記錄已經不被其餘事務引用,則purge完成真正的刪除

 

7.6 事務隔離級別

  READ UNCOMMITTED(讀未提交):事務隔離最低的級別,可是存在髒讀的問題

  READ COMMITED(讀提交):ORACLE和SQL SERVER默認的隔離級別,解決了髒讀,可是一個事務屢次讀取的內容不一樣,出現了不可重複讀的問題。

  READ REPEATABLE(可重複讀):innodb引擎的默認事務隔離級別,解決了不可重複讀的問題,可是產生了幻讀,innodb經過Next-key lock解決了幻讀。

  SERIALIZABLE(可串行化):經過強制事務排序解決幻讀問題,會下降性能。

 

  可串行化中,InnoDB會對每一個select語句後加上LOCK IN SHARE MODE,也就是爲每一個讀加上共享鎖。該級別主要用於分佈式事務。

 

7.7 分佈式事務

  指容許多個獨立的事務資源參與到一個全局的事務中。

  全局事務要求在其中全部參與的事務要麼都提交,要麼都回滾。

  InnoDB的隔離級別要設置爲可串行化。

 

 

7.8 很差的習慣

  在循環中提交事務

  不要開啓自動提交事務 set auto_commit = 0

  使用自動回滾,存儲過程當中使用 declare exit handlerfor sqlexception rollback

相關文章
相關標籤/搜索