對B+樹與索引在MySQL中的認識

目錄算法


概述

  • 本質:數據庫維護某種數據結構以某種方式引用(指向)數據
  • 索引取捨原則:索引的結構組織要儘可能減小查找過程當中磁盤I/O的存取次數

B樹

知足的條件
  • d爲大於1的一個正整數,稱爲B-Tree的度
  • h爲一個正整數,稱爲B-Tree的高度
  • 每一個非葉子節點由n-1個key和n個指針組成,其中d<=n<=2d
  • 每一個葉子節點最少包含一個key和兩個指針,最多包含2d-1個key和2d個指針,葉節點的指針均爲null
  • 全部葉節點具備相同的深度,等於樹高h
  • key和指針互相間隔,節點兩端是指針
  • 一個節點中的key從左到右非遞減排列
  • 全部節點組成樹結構
  • 每一個指針要麼爲null,要麼指向另一個節點
  • 一個度爲d的B-Tree,設其索引N個key,則其樹高h的上限爲logd((N+1)/2),檢索一個key查找節點的個數的漸進複雜度爲logd(N)
更新後的操做
  • 插入刪除新的數據記錄會破壞B-Tree的性質,所以在插入刪除時,須要對樹進行一個分裂、合併、轉移等操做以保持B-Tree性質

B+樹

  • 每一個節點的指針上限爲2d而不是2d+1
  • 內節點不存儲data,只存儲key
  • 葉子節點不存儲指針
  • 在經典B+樹的基礎上,增長了順序訪問指針-->提升區間訪問的性能數據庫

爲何使用B/B+樹?

主存讀取
  • 當系統須要讀取主存時,則將地址信號放到地址總線上傳給主存
  • 主存讀到地址信號後,解析信號並定位到指定存儲單元,而後將此存儲單元數據放到數據總線上,供其它部件讀取
  • 主存存取的時間僅與存取次數呈線性關係,由於不存在機械操做,兩次存取的數據的「距離」不會對時間有任何影響
磁盤存取原理
  • 磁盤轉動,每一個磁頭不動,負責讀取內容
  • 不過已經有了多磁頭獨立技術
  • 局部性原理
  • 磁盤預讀:長度通常以頁的整數倍爲單位

MyISAM索引實現

  • 使用B+樹做爲索引結構,data存放數據記錄的地址
  • 索引文件與數據文件分離
  • 主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,而輔助索引的key能夠重複
  • 非彙集:MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,則取出其data域的值,而後以data域的值爲地址,讀取相應數據記錄緩存

.MYI文件的組成
  • 整個索引文件的基本信息state
  • 各索引的限制信息base
  • 各索引的定義信息keydef
  • 各索引記錄的概要信息recinfo
讀取索引的流程
  • query請求,直接讀取key cache中的cache block,有就返回
  • 沒有就到.MYI文件中以file block方式讀取數據
  • 再以相同的格式存取key cache
  • 再將key cache中的數據返回

InnoDB索引實現

  • 也是使用B+樹
第一個與MyISAM的不一樣點
  • 第一個重大區別是InnoDB的數據文件自己就是索引文件,表數據文件自己就是按B+Tree組織的一個索引結構
  • InnoDB的數據文件自己要按主鍵彙集
  • 因此InnoDB要求表必須有主鍵(MyISAM能夠沒有)
  • 沒有顯式指定,自動選擇惟一標識列
  • 不存在的話,生成6個字節長整型的隱含字段
第二個與MyISAM的不一樣點
  • InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址
  • 換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域
  • 輔助索引搜索須要檢索兩遍索引:首先檢索輔助索引得到主鍵,而後用主鍵到主索引中檢索得到記錄
得出的優化點
  • 不建議使用過長的字段做爲主鍵,由於全部輔助索引都引用主索引,過長的主索引會令輔助索引變得過大
  • 用非單調的字段做爲主鍵在InnoDB中也很差,由於InnoDB數據文件自己是一顆B+Tree,非單調的主鍵會形成在插入新記錄時數據文件爲了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段做爲主鍵就很不錯了
  • 聚簇索引鍵被更新形成的成本除了索引數據可能會移動,相關的全部記錄數據也要移動

索引使用策略及優化

全列匹配
  • 按照索引中全部列進行精確匹配(這裏精確匹配指「=」或「IN」匹配)時,索引能夠被用到
  • 理論上索引對順序是敏感的,可是因爲MySQL的查詢優化器會自動調整where子句的條件順序以使用適合的索引
最左前綴匹配
  • 當查詢條件精確匹配索引的左邊連續一個或幾個列時,索引能夠被用到
查詢條件用到了索引中列的精確匹配,可是中間某個條件未提供
  • 只能用到索引中,從中間斷開前的列
  • 應對
  • 能夠增長輔助索引
  • 當中間條件選項較少時,用隔離列的方式,使用IN包含
  • 看狀況,比較創建
查詢條件沒有指定索引第一列
  • 不知足使用索引的條件
匹配某列的前綴字符串
  • 可使用索引
  • 若是通配符%不出如今開頭,則能夠用到索引,但根據具體狀況不一樣可能只會用其中一個前綴
範圍查詢
  • 範圍列能夠用到索引(必須是最左前綴),可是範圍列後面的列沒法用到索引
  • 同時,索引最多用於一個範圍列,所以若是查詢條件中有兩個範圍列則沒法全用到索引
  • 僅用explain可能沒法區分範圍索引和多值匹配
查詢條件中含有函數/表達式
  • 通常不使用哦
  • 手工算好再代入

索引選擇性與前綴索引

MyISAM與InnoDB基數統計方式
  • MyisAM索引的基數值(Cardinality,show index 命令能夠看見)是精確的,InnoDB則是估計值
  • MyisAM統計信息是保存磁盤中,在alter表或Analyze table操做更新此信息
  • 而InnoDB則是在表第一次打開的時候估計值保存在緩存區內
不建議創建索引的狀況
  • 表記錄比較少
  • 索引的選擇性低:不重複的索引值(也叫基數,Cardinality)與表記錄數(#T)的比值
前綴索引
  • 用列的前綴代替整個列做爲索引key,當前綴長度合適時,能夠作到既使得前綴索引的選擇性接近全列索引,同時由於索引key變短而減小了索引文件的大小和維護開銷
缺點
  • 不能用於ORDER BY和GROUP BY操做
  • 也不能用於Covering index(即當索引自己包含查詢所需所有數據時,再也不訪問數據文件自己)

InnoDB主鍵選擇與插入優化

  • 若是沒有特別的須要,請永遠使用一個與業務無關的自增字段做爲主鍵
  • InnoDB使用匯集索引,數據記錄自己被存於主索引(一顆B+Tree)的葉子節點上
  • 這就要求同一個葉子節點內(大小爲一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,所以每當有一條新的記錄插入時,MySQL會根據其主鍵將其插入適當的節點和位置,若是頁面達到裝載因子(InnoDB默認爲15/16),則開闢一個新的頁(節點)
  • 若是使用非自增主鍵,每次插入近似隨機,容易引發數據的移動,從新讀目標頁面,碎片也多了,雖然也能夠用OPTIMIZE TABLE重建優化,但麻煩啊

參考資料

  • 圖片來源網絡
  • 《高性能MySQL》
相關文章
相關標籤/搜索