1、索引不是萬能
- 數據行數少的狀況下,索引效率沒什麼做用
- 當數據重複度大,好比高於 10% 的時候,也不須要對這個字段使用索引
2、索引類型
1.功能邏輯分類
普通索引 |
|
惟一索引 |
|
主鍵索引 |
|
全文索引 |
|
2.物理實現分類
彙集索引 |
|
非彙集索引 |
|
3.字段個數分類
單一索引 | 索引列爲一列 |
聯合索引 | 多個列組合在一塊兒建立 |
4.索引片中包含的匹配列的數量不一樣
窄索引 | 包含索引列數爲 1 或 2 |
寬索引 | 包含的索引列數大於 2) |
3、聯合索引的最左原則
聯合索引(x,y,z),索引查詢,必須出現由左到右的查詢條件纔有效(不是編寫SQL的where順序,是要查y的時候,必有x做爲查詢條件才能夠),從左到右的使用索引中的字段sql
4、爲何用B+樹來作索引
名稱 | 樹形 | 侷限性 |
二叉樹 |
|
|
平衡二叉樹 |
|
|
BTree |
|
|
B+Tree |
|
- 磁盤的 I/O 操做次數對索引的使用效率相當重要
- 雖然傳統的二叉樹數據結構查找數據的效率高,但很容易增長磁盤 I/O 操做的次數,影響索引使用的效率
- 在構造索引的時候,更傾向於採用「矮胖」的數據結構
- B 樹和 B+ 樹均可以做爲索引的數據結構,在 MySQL 中採用的是 B+ 樹,B+ 樹在查詢性能上更穩定,在磁盤頁大小相同的狀況下,樹的構造更加矮胖,所須要進行的磁盤 I/O 次數更少
- 子節點進行了鏈表連接更適合進行關鍵字的範圍查詢
5、Hash索引
- Hash 自己是一個函數,又被稱爲散列函數,它能夠幫助咱們大幅提高檢索數據的效率
- 只須要一次交互就能夠完成查找,效率很是高
Hash | B+Tree | |
範圍查詢 |
|
|
聯合索引的最左側原則 |
|
|
ORDER BY 排序 |
|
|
模糊查詢 |
|
|
等值查詢 |
|
|
MySQL 中的 Memory 存儲引擎支持 Hash 存儲,其餘不支持,如InnoDB數據庫
6、Mysql 自適應 Hash 索引
MySQL 的 InnoDB 存儲引擎還有個「自適應 Hash 索引」的功能,就是當某個索引值使用很是頻繁的時候,它會在 B+ 樹索引的基礎上再建立一個 Hash 索引,這樣讓 B+ 樹也具有了 Hash 索引的優勢,這個功能不須要人工干預數組
- 自適應哈希索引只保存熱數據(常常被使用到的數據),並不是全表數據。所以數據量並不會很大,可讓自適應Hash放到緩衝池中,也就是InnoDB buffer pool,進一步提高查找效率
- InnoDB中的自適應Hash至關因而「索引的索引」,採用Hash索引存儲的是B+樹索引中的頁面的地址
- 自適應Hash採用Hash函數映射到一個哈希表中,因此對於字典類型的數據查找很是方便哈希表是數組+鏈表的形式
InnoDB自己不支持Hash,可是提供自適應Hash索引,不須要用戶來操做,而是存儲引擎自動完成的。自適應Hash也是InnoDB三大關鍵特性之一數據結構
7、建立索引規律
索引太多了,在更新數據的時候,若是涉及到索引更新,就會形成負擔函數
須要建立索引的狀況性能
- 字段的數值有惟一性的限制
- 頻繁做爲 WHERE 查詢條件的字段,尤爲在數據表大的狀況下
- 須要常常 GROUP BY 和 ORDER BY 的列
- 多個單列索引在多條件查詢時只會生效一個索引(MySQL 會選擇其中一個限制最嚴格的做爲索引),多條件聯合查詢的時候最好建立聯合索引
- UPDATE、DELETE 的 WHERE 條件列,通常也須要建立索引
- DISTINCT 字段須要建立索引
不須要建立索引的狀況優化
- WHERE 條件(包括 GROUP BY、ORDER BY)裏用不到的字段不須要建立索引
- 若是表記錄太少,好比少於 1000 個,那麼是不須要建立索引的
- 字段中若是有大量重複數據,也不用建立索引
- 頻繁更新的字段不必定要建立索引,更新數據的時候,也須要更新索引,若是索引太多,在更新索引的時候也會形成負擔,從而影響效率
索引失效的狀況搜索引擎
- 若是索引進行了表達式計算,則會失效
- 若是對索引使用函數,會形成失效
- 在 WHERE 子句中,若是在 OR 前的條件列進行了索引,而在 OR 後的條件列沒有進行索引,那麼索引會失效,由於 OR 的含義就是兩個只要知足一個便可,所以只有一個條件列進行了索引是沒有意義的,只要有條件列沒有進行索引,就會進行全表掃描,所以索引的條件列也會失效
- 當咱們使用 LIKE 進行模糊查詢的時候,前面不能是 %,如%xxx
- 索引列儘可能設置爲 NOT NULL 約束
- 聯合索引的時候要注意最左原則
8、索引片和過濾因子
- SQL 查詢語句在執行中須要掃描的一個索引片斷
- 索引片越寬,須要順序掃描的索引頁就越多
- 索引片越窄,就會減小索引訪問的開銷
經過寬索引避免回表
學生表(學號,姓名,課程ID,課程名),主鍵(學號)spa
select 學號,姓名,課程ID,課程名 from 學生表 where 課程ID in (1,2,3);
窄索引(課程ID)設計
- 經過窄索引,找到主鍵(定位數據行)
- 根據主鍵(數據行),回表查找相應數據
- 取出select須要的數據
寬索引(課程ID,姓名,課程名)
- 直接經過寬索引找到select須要的數據
優勢:經過寬索引將 SELECT 中須要用到的列(主鍵列能夠除外)都設置在寬索引中,這樣就避免了回表掃描的狀況
缺點:寬索引須要順序掃描的索引頁不少
過濾因子
- 描述了謂詞的選擇性。在 WHERE 條件語句中,每一個條件都稱爲一個謂詞,謂詞的選擇性也等於知足這個條件列的記錄數除以總記錄數的比例
學生表(學號,姓名,課程ID,性別,年齡)
- 假設重複率:性別50%,姓名14%,課程ID28%,年齡43%
- 性別,年齡不是好過濾因子
- 聯合過濾因子有更高的過濾能力
- 須要注意一個條件,那就是條件列的關聯性應該儘可能相互獨立,不然若是列與列之間具備相關性,聯合過濾因子的能力就會降低不少
- 好比城市名稱和電話區號就有強相關性,這兩個列組合到一塊兒不會增強過濾效果
- 過濾因子決定了索引片的大小
- 過濾因子的條件過濾能力越強,知足條件的記錄數就越少,SQL 查詢須要掃描的索引片也就越小
- 若是沒有選擇好索引片中的過濾因子,就會形成索引片中的記錄數過多的狀況
三星索引
- 在 WHERE 條件語句中,找到全部等值謂詞中的條件列,將它們做爲索引片中的開始列
- 將 GROUP BY 和 ORDER BY 中的列加入到索引中
- 將 SELECT 字段中剩餘的列加入到索引片中
- 經過索引查找符合條件的記錄,就須要將 WHERE 子句中的等值謂詞列加入到索引片中,這樣索引的過濾能力越強,最終掃描的數據行就越少
- 要對數據記錄分組或者排序,都須要從新掃描數據記錄。爲了不進行 file sort 排序,能夠把 GROUP BY 和 ORDER BY 中涉及到的列加入到索引中
- 建立了索引就會按照索引的順序來存儲數據,這樣再對這些數據按照某個字段進行分組或者排序的時候,就會提高效率
很難存在理想的索引設計
- 採用三星索引會讓索引片變寬,這樣每一個頁可以存儲的索引數據就會變少,從而增長了頁加載的數量
- 從另外一個角度來看,若是數據量很大,好比有 1000 萬行數據,過多索引所須要的磁盤空間可能會成爲一個問題,對緩衝池所需空間的壓力也會增長,增長了索引維護的成本
- 若是爲全部的查詢語句都設計理想的三星索引,就會讓數據表中的索引個數過多,這樣索引維護的成本也會增長
- 當添加一條記錄的時候,就須要在每個索引上都添加相應的行(存儲對應的主鍵值)
- 假設添加一行記錄的時間成本是 10ms(磁盤隨機讀取一個頁的時間)
- 若是咱們建立了 10 個索引,添加一條記錄的時間就可能變成 0.1s,若是是添加 10 條記錄呢?就會花費近 1s 的時間
- 從索引維護的成原本看消耗仍是很高的
- 固然對於數據庫來講,數據的更新不必定立刻回寫到磁盤上,但即便不及時將髒頁進行回寫,也會形成緩衝池中的空間佔用過多,髒頁過多的狀況