MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。
可以得到索引的本質:索引是數據結構。
索引的優勢:(1)類似大學圖書館建書目索引,提高數據檢索的效率,降低數據庫的IO成本;(2)通過索引列對數據進行排序,降低數據排序的成本,降低了CPU的消耗。
索引的劣勢:(1)雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERT、UPDATE和DELETE。
因爲更新表時,MySQL不僅要保存數據,還要保存一下索引文件每次更新添加了索引列的字段,
都會調整因爲更新所帶來的鍵值變化後的索引信息;(2)實際上索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄,所以索引列也是要佔用空間的。
MySQL的索引所使用的數據結構是B+樹,而不是B樹。B-樹的關鍵字和記錄是放在一起的,葉子節點可以看作外部節點,不包含任何信息;B+樹的非葉子節點中只有關鍵字和指向下一個節點的索引,記錄只放在葉子節點中。
選擇B+樹的原因是:在有限的內存下:
1) B+樹的磁盤讀寫代價更低
B+樹的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B 樹更小。如果把所有同一內部 結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找 的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
2) B+樹的查詢效率更加穩定
由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必 須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
聚簇索引與非聚簇索引:
聚簇索引並不是一種單獨的索引類型,而是一種數據存儲方式。術語‘聚簇’表示數據行和相鄰的鍵值聚簇的存儲在一起。
按照聚簇索引排列順序,查詢顯示一定範圍數據的時候,由於數據都是緊密相連,數據庫不不用從多個數據塊中提取數據,所以節省了大量的io操作。
對於mysql數據庫目前只有innodb數據引擎支持聚簇索引,而Myisam並不支持聚簇索引。
由於數據物理存儲排序方式只能有一種,所以每個Mysql的表只能有一個聚簇索引。一般情況下就是該表的主鍵。
爲了充分利用聚簇索引的聚簇的特性,所以innodb表的主鍵列儘量選用有序的順序id,而不建議用無序的id,比如uuid這種。
MySQL索引分類:
- 單值索引 即一個索引只包含單個列,一個表可以有多個單列索引
- 唯一索引 索引列的值必須唯一,但允許有空值
- 主鍵索引 設定爲主鍵後數據庫會自動建立索引,innodb爲聚簇索引
- 複合索引 即一個索引包含多個列
需要創建索引的情況:
- 主鍵自動建立唯一索引
- 頻繁作爲查詢條件的字段應該創建索引
- 查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
- 查詢中統計或者分組字段
不要創建索引的情況:
- 表記錄太少
- 經常增刪改的表或者字段
- Where條件裏用不到的字段不創建索引
- 過濾性不好的不適合建索引
單表查詢索引優化:
- 全值匹配我最愛:如果where中有多個等值判斷條件,則應該創建這些條件屬性的複合索引,這樣效率最高。
- 最佳左前綴法則:如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始並且不跳過索引中的列。
- 不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描
- 存儲引擎不能使用索引中範圍條件右邊的列
- mysql 在使用不等於(!= 或者<>)的時候無法使用索引會導致全表掃描
- is not null 也無法使用索引,但是is null是可以使用索引的
- like以通配符開頭('%abc...')mysql索引失效會變成全表掃描的操作
- 字符串不加單引號索引失效
關聯查詢索引優化:
- 保證被驅動表的join字段已經被索引:驅動表是join左邊的表,被驅動表是join右邊的表(忽略right join,因爲可以由left join替代)
- left join 時,選擇小表作爲驅動表,大表作爲被驅動表。
- inner join 時,mysql會自己幫你把小結果集的表選爲驅動表。
- 子查詢儘量不要放在被驅動表,有可能使用不到索引。(因爲子查詢出來的表是一個不存在的表,無法創建索引)
- 能夠直接多表關聯的儘量直接關聯,不用子查詢。
子查詢索引優化:儘量不要使用not in 或者 not exists,用left outer join ... on ... where xxx is null 替代。因爲用not in(子查詢) 的話,子查詢出來的結果是一個不存在的表,只能全掃描,無法使用索引。而後面的寫法可以使用索引。
排序查詢索引優化:對於,排序查詢的優化,關鍵就是使用索引現成的排序,而避免出現using filesort。有三條原則:
- 如果查詢沒有過濾條件,比如where子句或者limit等,就不會使用索引,即使有索引的列組合與排序的列組合一模一樣。
- 如果排序的列組合的順序與索引的順序不同,也會使索引無效,導致using filesort。
- 如果排序的不同列之間的排序順序不同,比如一列是升序排序,另一列是降序排列,那麼也會使索引無效,導致using filesort。但是同時是升序或者降序是可以使用索引的。(其實,這點我是無法理解的,爲什麼排序順序不同就無法使用索引,這可能與複合索引的具體實現有關)
- 因爲複合索引的其中一個列作爲範圍條件的話,後面的列就不在會使用索引,所以當範圍條件和group by 或者 order by 的字段出現二選一時 ,優先觀察條件字段的過濾數量,如果過濾的數據足夠多,而需要排序的數據並不多時,優先把索引放在範圍字段上。反之,亦然。
分組查詢索引優化:group by 使用索引的原則幾乎跟order by一致 ,唯一區別是groupby 即使沒有過濾條件用到索引,也可以直接使用索引。(因爲group by 分組就是先排序再分組的)
什麼是覆蓋索引?簡單說就是,select 到 from 之間查詢的列 <=使用的索引列+主鍵。通俗的說就是,你想查詢哪些列,就在select子句中寫明,不要用*代替,這樣做的話,即使在不能使用索引的情況,也能勉強用上一點索引,來提升一點速度。(這點,我也是不理解的,很懵逼。。,爲啥呢?)