(1)MySql索引基礎

本文是學習MySQL索引知識後進行得整理,部分圖片來源馬士兵老師的公開課,僅做筆記使用mysql

1、MySql架構圖

MySql架構圖

2、幾種常見的數據結構用於索引結構分析

一、hash表

hash表結構
缺點:
sql

  1. 利用Hash存儲索引的話,須要將全部的數據文件添加到內存中,比較耗費內存空間。
  2. hash適用於等值查詢,可是在實際工做環境下範圍查詢的操做更多,因此hash就不太適用了。

二、BST(二分查找樹)、AVL(平衡二叉樹)、紅黑樹

①BST、AVL
BST與AVL介紹
②紅黑樹
紅黑( Red 一 bIack )樹是一種自平衡二叉查找樹. 1972 年由 RudOlfBaye 潑明.它與 AvL 樹相似,都在插入和刪除操做時能經過旋轉操做時,保持二叉查找樹的平衡,以便能得到高效的查找性能.它能夠在 O ( Iogn )時間內作查找,插入和刪除等操做。紅黑樹是 2-3-4樹的一種等同,但有些紅黑樹設定只能左邊是紅樹.這種狀況就是 2-3 樹的一種等同了。對於 AVL 樹來講,紅黑樹犧牲了部分平衡性以換取插入/刪除操做時少許的旋轉操做,總體來講性能要優於 AVL 樹。
①②缺點:
不管是BST、AVL、紅黑樹,都會由於樹的深度過深,而形成磁盤IO次數過多,影響數據的讀取效率。




數據庫

三、B樹

B樹的特色:服務器

  1. 全部的鍵值分佈在整顆樹中。
  2. 搜索有可能在非葉子節點結束,在關鍵字全集內作一次查找,性能逼近二分查找。
  3. 每一個節點最多擁有m個子樹。
  4. 根節點至少有兩個子樹。
  5. 分支節點至少擁有m/2顆子樹(除根節點和葉子節點外都是分支節點)
  6. 全部的葉子節點都在同一層,每一個節點最多能夠有m-1個key,而且以升序排列
    B樹的結構以及示例

總結:根據 B-Tree 的定義,可知檢索一次最多須要訪問 h 個節點。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每一個節點只須要一次 I/O 就能夠徹底載入。(操做系統中一頁大小一般是4KB)
每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,加之計算機存儲分配都是按頁對齊的,就實現了一個節點只需一次 I/O。
而檢索的時候,一次檢索最多須要 h-1 次 I/O(根節點常駐內存),其漸進複雜度爲
但在實際應用中,出度 d 是很是大的數字,一般超過 100,所以 h 很是小(一般不超過 3)。而其餘搜索二叉樹,h 明顯要深的多。因爲邏輯上很近的節點(父子)物理上可能很遠,沒法利用局部性,因此其它樹的 I/O 漸進複雜度也爲 O(h),效率明顯比 B-Tree 差不少。


數據結構

四、B+樹

Mysql的B+樹索引結構

注意:架構

  1. Mysql的存儲引擎的Innodb和MyISAM的B+樹索引結構的Data區域存放的值是不同的。Innodb的主鍵索引如圖中解釋的存放的是行數據,而輔助索引的key是索引列字段,data存放的是主鍵(經過輔助索引查找到主鍵,在經過主鍵到主鍵索引中查找到行數據叫回表);MyIsam存儲引擎的索引都是非聚簇索引,它的B+樹索引的Data區域存放的都是內存地址
  2. 索引分爲聚簇索引(Innodb存儲引擎的主鍵索引)和非聚簇索引(除Innodb存儲引擎的主鍵索引外)
  3. B+樹的只有葉子節點纔會存放data

B+Tree索引的性能分析性能

通常使用磁盤I/O次數評價索引結構的優劣
一、預讀:磁盤通常會順序向後讀取必定長度的數據(頁(4K)的整數倍)放入內存
二、局部性原理:當一個數據被用到時,其附近的數據也一般會立刻被使用
三、B+Tree節點的大小設爲等於一個頁,每次新建節點直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,就實現了一個節點的載入只需一次I/O
四、B+Tree的度d通常會超過100,所以h(樹的高度)很是小(通常爲3到5之間)



學習

3、索引(Innodb存儲引擎)

1. 索引簡述

索引是一種用於快速查找排序的數據結構。
優勢:
一、MySQL索引的創建對於MySQL的高效運行是很重要的,索引能夠大大提升MySQL的檢索速度;
二、幫助服務器避免排序和臨時表。
三、將隨機io變成順序io
注:可以減小磁盤IO的次數,從而提升檢索速度–>因爲磁盤數據的存取會通過尋道時間(速度慢、耗時)和旋轉時間(速度快);
缺點:雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行INSERT、UPDATE和DELETE。由於更新表時,MySQL不只要保存數據,還要保存一下索引文件。創建索引會佔用磁盤空間的索引文件





優化

2.索引分類

  1. 主鍵索引

基於該表主鍵自動生成成的索引,若是未給表定義主鍵,會查找該表中是否存在非空、整形、惟一索引做爲其主鍵(可經過select _rowid from 表名查看),若都不知足會隱式生成一個rowid做爲主鍵(沒法直接查到)spa

  1. 惟一索引

基於表的惟一列生成的索引,容許爲空值

3 普通索引

非主鍵,非惟一列的索引

  1. 全文索引

將存儲於數據庫中的整本書或整篇文章中任意內容信息查找出來,如大量級的文字中如like %關鍵字%,普通索引的效率與全文索引相比是很是低的

  1. 組合索引

上面1-4講的只是單索引
create index id_name_subject on teacher(name, subject); 組合索引key(name ,subject)
索引中的key存放了name和subject兩個字段,而data區域存放主鍵

3.回表

在B+樹圖片中提到過回表的過程,如今在回顧一下
先從Innodb存儲引擎提及,Innodb有兩種索引,一種聚簇索引,一種普通索引;

  • 聚簇索引

Innodb必需要有一個聚簇索引,且只有一個。
如有主鍵的話,聚簇索引就是主鍵索引。
若沒有主鍵,會選擇一個非空的惟一鍵做爲聚簇索引
若沒有惟一鍵,則會生成一個6字節的rowid做爲聚簇索引


  • 普通索引

普通索引的key存的是name,葉子節點中的data區域存的主鍵id

回表: 好比有一張people表,裏面有一個普通索引index(name)
SQL爲;select * from people where name =‘zhangsan’
此時存儲引擎會根據普通索引name查詢到name=‘zhangsan’的對應的主鍵id,而後在根據主鍵id去聚簇索引中查詢到行數據,這個過程叫回表操做。

4.最左匹配原則

兩種方式: ①CBO-基於成本優化(默認),②RBO-基於規則優化

索引能夠簡單如一個列(a),也能夠複雜如多個列(a, b, c, d),即組合索引。若是是組合索引,那麼key也由多個列組成,同時,索引只能用於查找key是否存在(相等),遇到範圍查詢(>、<、between、like左匹配)等就不能進一步匹配了,後續退化爲線性查找。所以,列的排列順序決定了可命中索引的列數。

若有索引(a, b, c, d),查詢條件a = 1 and b = 2 and c > 3 and d = 4,則會在每一個節點依次命中a、b、c,沒法命中d。也就是最左前綴匹配原則。

=、in自動優化順序不須要考慮=、in等的順序,mysql會自動優化這些條件的順序,以匹配儘量多的索引列。

若有索引(a, b, c, d),查詢條件where c > 3 and b = 2 and a = 1 and d < 4與where a = 1 and c > 3 and b = 2 and d < 4等順序都是能夠的,MySQL的優化器會自動優化爲where a = 1 and b = 2 and c > 3 and d < 4,依次命中a、b、c。

--一張表table,組合索引爲(name,age,addr)
select * from table where name = 'zhangsan' and age = 10 and addr='hubei' --匹配(name,age,addr)
select * from table where name = 'zhangsan' and age = 10 --匹配到name,age
select * from table where name = 'zhangsan' --只走索引name
select * from table where age = 10 --丟失頭部索引name,不會走索引
select * from table where age = 10 and name = 'zhangsan' --匹配到name,age,sql優化器會優化
select * from table where name = 'zhangsan' and addr = ‘湖北’ --name走索引,addr不會,因爲中間age斷了
--上述狀況在select * from table where條件下, 後面若是沒有name就不會走索引。中間斷了,後面就不會繼續走索引

SELECT NAME FROM people  WHERE age =40 --會走索引,---覆蓋索引

5.索引覆蓋

一張表table,組合索引爲(name,age,addr),自增主鍵爲id

SELECT NAME FROM people  WHERE age =40
SELECT id,NAME FROM people  WHERE age =40
SELECT id,NAME,idCard FROM people  WHERE age =40
SELECT id,NAME,idCard FROM people  WHERE name='zhangsan'

第一條SQL查詢條件與須要查詢的字段都在組合索引(name,age,addr)中,因此會走索引,這種狀況就是索引覆蓋,此時就不須要在進行回表操做了,會直接在組合索引中查詢到值,減小了磁盤IO的次數。
至於第二條SQL,也是索引覆蓋,由於id爲主鍵,在組合索引中除了有name,age,addr外還有data中的主鍵id,因此能夠直接在組合索引中拿到值。
第三條SQL不會走索引 ,由於查詢的列有IDcard,該列不在組合索引(name,age,addr)中,因此會全表掃描。
第四條SQL會走索引name,但因爲查詢的列有IDCard,因此會在組合索引查詢到對應的主鍵id,在經過聚簇索引中查詢到對應行數據取出IDcard,這個過程會有回表操做,效率比走覆蓋索引低。


6.索引下推(ICP) mysql5.6及以後

ICP:Index Condition Pushdown

一張表people,組合索引爲(name,age,addr),自增主鍵爲id

SELECT * FROM people  WHERE age >20 AND  NAME LIKE 'zhnags%'

上面的SQL有兩種執行可能的過程
一、根據組合索引查詢知足name以「zhangs」開頭的索引,而後回表查詢出相應的全行數據,而後再篩選出知足年齡age大於10的數據
二、根據組合索引查詢知足name以「zhangs」開頭的索引,而後直接在磁盤中再篩選出年齡大於10的索引,以後再回表查詢全行數據

根據上面兩種可能,能夠明顯看出第二種效率更高,減小了回表了次數,從而提升效率

mysql5.6以前版本

在沒有索引下推以前,①先從存儲引擎中拉取name=‘zhangs’的行數據②mysql Server 再根據age進行數據篩選

mysql5.6及以後版本

有索引下推以後,根據組合索引查詢知足name以「zhangs」開頭的索引,而後直接在磁盤中再篩選出年齡大於10的索引,以後再回表查詢全行數據

實踐 mysql5.7版本索引下推

索引下推總結:

優勢:索引下推在普通索引上的優化,能夠有效減小回表的次數,大大提高了查詢的效率。

注:關閉索引下推可使用以下命令

set optimizer_switch='index_condition_pushdown=off';

7.謂詞下推

有兩張表A,B,id分別爲各自的主鍵

select * from A Join B on A.id = B.id

上面的SQL有兩種執行可能
①先作錶鏈接,在作查詢須要的字段
②先取出全部須要的字段,而後在作表關聯 --------- 謂詞下推
MySQL優化器會進行優化成方式②,使用第②種能減小IO量,效率更高



---------------------------若有錯誤之處,歡迎指出

相關文章
相關標籤/搜索