徹底搞懂數據庫索引

一、索引基礎

1.索引定義

在數據之外,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。

2.索引類型

用於提高讀寫效率的數據結構有很多,這裏先介紹常見的 3 種,分別是:

  • 哈希表
  • 有序數組
  • 搜索樹(主要)

3.搜索樹索引——B+樹

根據葉子結點的內容,索引類型分爲主鍵索引和非主鍵索引。

  • 主鍵索引的葉子結點存的是整條記錄主鍵索引也被稱爲聚簇索引(clustered index)。
  • 非主鍵索引的葉子結點存的是主鍵的值,非主鍵索引也被稱爲二級索引(secondary index)/ 普通索引 / 輔助索引。

那麼,基於主鍵索引和非主鍵索引的查詢有什麼區別?

  • 如果語句是 select * from T where ID=500,即主鍵查詢,則只需要搜索 ID 這棵樹。
  • 如果語句是 select * from T where k=5,即非主鍵索引查詢,則需要先搜索 k 索引樹,得到 ID 的值爲 500,再到 ID 索引樹搜索一次。從非主鍵索引回到主鍵索引的過程稱爲回表。

也就是說,基於非主鍵索引的查詢需要多掃描一棵索引樹。因此,我們在應用中應該儘量使用主鍵查詢。而從存儲空間的角度講,因爲非主鍵索引樹的葉結點存放的是主鍵的值,那麼,應該考慮讓主鍵的字段儘量短,這樣非主鍵索引的葉子結點就越小,非主鍵索引佔用的空間也就越小。一般情況下,建議創建一個自增主鍵,這樣非主鍵索引佔用的空間最小。

4. 聯合索引

聯合索引是指對表上的多個列進行索引

聯合索引 (a, b) 是根據 a, b 進行排序(先根據 a 排序,如果 a 相同則根據 b 排序)。因此,下列語句可以直接使用聯合索引得到結果(事實上,也就是用到了最左前綴原則):

  • select … from xxx where a=xxx;
  • select … from xxx where a=xxx order by b;

而下列語句則不能使用聯合查詢:

  • select … from xxx where b=xxx;

對於聯合索引 (a, b, c),下列語句同樣可以直接通過聯合索引得到結果:

  • select … from xxx where a=xxx order by b;
  • select … from xxx where a=xxx and b=xxx order by c;

而下列語句則不行,需要執行一次 filesort 排序操作。

  • select … from xxx where a=xxx order by c;

5.最左前綴原則

不只是索引的全部定義,只要滿足最左前綴,就可以利用索引來加速檢索。這個最左前綴可以是聯合索引的最左 N 個字段,也可以是字符串索引的最左 M 個字符。利用索引的 “最左前綴” 原則來定位記錄,避免重複定義索引。

因此,基於最左前綴原則,我們在定義聯合索引的時候,考慮如何安排索引內的字段順序就至關重要了!評估的標準就是索引的複用能力,比如,當已經有了 (a,b) 字段的索引,一般就不需要再單獨在 a 上建立索引了。

6.回表和覆蓋索引

如果where子句中的一個條件是非主鍵索引,那麼查詢的時候,先通過非主鍵索引定位到主鍵索引(主鍵位於非主鍵索引搜索樹的葉子節點);然後通過主鍵索引定位到查詢的內容。在這個過程中,回到主鍵索引樹的過程,稱爲回表。

但是當我們的查詢內容是主鍵值,那麼可以直接提供查詢結果,不需要回表。也就是說,在這個查詢裏,非主鍵索引 已經 “覆蓋了” 我們的查詢需求,故稱爲覆蓋索引。

總結:覆蓋索引就是從輔助索引中就能直接得到查詢結果,而不需要回表到聚簇索引中進行再次查詢,所以可以減少搜索次數(不需要從輔助索引樹回表到聚簇索引樹),或者說減少 IO 操作(通過輔助索引樹可以一次性從磁盤載入更多節點),從而提升性能。

7.索引下推

MySQL 5.6 引入了索引下推優化,可以在索引遍歷過程中,對索引中包含的字段先做判斷,過濾掉不符合條件的記錄,減少回表字數。


二、前綴索引:

當索引是很長的字符序列時,這個索引將會很佔內存,而且會很慢,這時候就會用到前綴索引了。所謂的前綴索引就是去索引的前面幾個字母作爲索引,但是要降低索引的重複率,索引我們還必須要判斷前綴索引的重複率。

mysql> select 1.0*count (distinct name)/count (*) from test 

這是比較整個 name 的重複率,當時這是最好的情況。然後分別截取 name 字符的前幾個字母,最後選取的計算值要接近整個取整個 name 時得出的計算值,然後再選中佔用空間小的。由上面執行的結果可知應選中 name 的前 4 個字母作爲索引最爲適合。

創建索引:

mysql> alter table test add key(name(4));

三、text和blob類型對比

blob 可變長二進制數據,最多存216-1個字節
text 最多存216-1個字節

在這裏插入圖片描述


四、使用索引

explain的type字段:

  • ALL: 全表掃描
  • index: 索引全掃描
  • range: 索引範圍掃描
  • ref: 使用非唯一索引掃描
  • eq_ref: 使用唯一索引掃描

增加普通的 BTREE 索引

 ALTER TABLE dept ADD INDEX index_remark (`remark`); 

增加聯合 BTREE 索引

 ALTER TABLE dept ADD INDEX index_all (`deptName`,`remark`,`createDate`);  

上面兩個 SQL 索引相同 Type 不同是因爲 BTREE 索引中匹配最左前綴 比如給 col1+col2+col3 字段上加聯合索引能夠被包含

col1+col2 、col1+col2+col3、col1+col3 使用 (順序沒有影響 比如 where col1=? and col2=? 和 where col2=? and col1=? 結果一樣)

使用聯合索引 相當於一下子創建瞭如上的三個索引,這就是聯合索引的好處


五、存在索引但不能使用索引的經典場景

1. 以 % 開頭的 LIKE 查詢不能使用 BTREE 索引

explain select deptName,remark,createDate from dept where deptName like'%2' and remark = 'test'and createDate ='2018-07-22'; type index

2. 複合索引時 不符合最左匹配原則 (上面已經提到)

explain select deptName,remark,createDate from dept where remark = 'test'and createDate ='2018-07-22'; type index

複合索引最左匹配原則的成因:

Mysql 創建複合索引的規則是首先會對複合索引最左邊,也就是第一個字段的索引進行排序

在第一個字段排序的基礎上,在對第二個字段進行排序,所以直接使用第二個字段是沒有順序的

3. 用 or 分隔開的條件,如果 or 前的條件中的列有索引,後面的列中沒有索引,那麼涉及到的索引都不會使用到

explain select deptName,remark,createDate from dept where deptName =‘2’ and remark = 'test’and createDate =‘2018-07-22’ or salary =200; type ALL


六、Show Profile

1.Show Profile 是 mysql 提供的可以用來分析當前會話中 sql 語句執行的資源消耗情況的工具,可用於 sql 調優的測量。默認情況下處於關閉狀態,並保存最近 15 次的運行結果。

2.通過 set profiling = on 開啓show profile;通過 show profiles 查看 sql 語句的耗時時間,然後通過 show profile 命令對耗時時間長的 sql 語句進行診斷。

3.show profile 的常用查詢參數。

①ALL:顯示所有的開銷信息。

②BLOCK IO:顯示塊 IO 開銷。

③CONTEXT SWITCHES:上下文切換開銷。

④CPU:顯示 CPU 開銷信息。

⑤IPC:顯示發送和接收開銷信息。

⑥MEMORY:顯示內存開銷信息。

⑦PAGE FAULTS:顯示頁面錯誤開銷信息。

⑧SOURCE:顯示和 Source_function,Source_file,Source_line 相關的開銷信息。

⑨SWAPS:顯示交換次數開銷信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章