Mysql索引原理及查詢優化
阿新 • • 發佈:2021-09-13
Mysql查詢變慢了,你可能最先想到的就是,索引加了沒?
1. 基本概念
-
聚簇索引:具有一下兩種特性的索引:
- 使用記錄主鍵值的大小進行記錄和頁的排序
- 頁內的記錄是按照主鍵的大小順序排成一個單向連結串列
- 各個存放使用者記錄的頁也是根據頁中使用者記錄的主鍵大小順序排成一個雙向連結串列
- 存放目錄項記錄的頁分為不同的層次,在同一層次中的頁也是根據頁中目錄項記錄的主鍵大小順序排成一個雙向連結串列
- 葉子節點儲存的是完整的使用者記錄(完整指的是這個記錄中儲存了所有列的值(包括隱藏列))
InnoDB儲存引擎會自動的為我們建立聚簇索引。另外有趣的一點是,在
InnoDB
儲存引擎中,聚簇索引
就是資料的儲存方式(所有的使用者記錄都儲存在了葉子節點
- 使用記錄主鍵值的大小進行記錄和頁的排序
-
二級索引:具有一下特點(例如使用列
column
)- 使用記錄
column
列的大小進行記錄和頁的排序- 頁內的記錄是按照
column
列的大小順序排成一個單向連結串列。 - 各個存放使用者記錄的頁也是根據頁中記錄的
column
列大小順序排成一個雙向連結串列。 - 存放目錄項記錄的頁分為不同的層次,在同一層次中的頁也是根據頁中目錄項記錄的
column
列大小順序排成一個雙向連結串列。
- 頁內的記錄是按照
B+
樹的葉子節點儲存的並不是完整的使用者記錄,而只是column列+主鍵
這兩個列的值。(回表的理論關注這裡),如果需要查詢column列和主鍵以外的列,這裡就需要根據聚簇索引(主鍵)來返回查詢的列- 目錄項記錄中不再是
主鍵+頁號
的搭配,而變成了column列+頁號
的搭配。
- 使用記錄
-
聯合索引:本質上也是一個二級索引,只是以多個列作為索引值
-
列的基數:
列的基數
指的是某一列中不重複資料的個數,比方說某個列包含值2, 5, 8, 2, 5, 8, 2, 5, 8
,雖然有9
條記錄,但該列的基數卻是3
。也就是說,在記錄行數一定的情況下,列的基數越大,該列中的值越分散,列的基數越小,該列中的值越集中。這個列的基數
指標非常重要,直接影響我們是否能有效的利用索引。
2. 索引的優劣勢
- 優勢:
- 加快查詢速度
- 劣勢
- 空間上的代價:需要額外的儲存頁儲存索引
- 時間上的代價:對錶中的資料進行增、刪、改操作時,都需要去修改各個
B+
3. 建立索引的優化
- 聚簇索引(主鍵)
- 方案:主鍵能夠做到自增,或者以遞增的形式生成
- 原因:主鍵不自增會造成記錄在頁的連結串列中間插入,造成頁面分裂和記錄移位,插入效能很差
- 二級索引:
- 只為用於搜尋、排序、分組的列建立索引
- 最好為那些列的基數大的列建立索引,為基數太小列的建立索引效果可能不好
- 儘量讓索引值佔用的位元組數小,在一頁中可以存放更多的索引,減少磁碟I/O可以加快查詢速度
- 不要建立重複索引,以列column 作為第一位的聯合索引和 只有一列column 作為索引的用處相同,不需要重複建立
4. 索引查詢的優化
索引的查詢優化主要是針對聯合索引,聯合索引比較特殊,比如以 a,b,c三列作為聯合索引的列,頁的記錄先按照a排序,再按照b排序,再按照c排序,那麼對於聯合索引的查詢,不需要根據列a查詢、排序、分組的話,聯合索引其實也沒有很大的使用者
- 若需要通過索引查詢,索引生效的條件是 存在 a,存在b,存在c,否則無效
- 左字首法則,如果使用like進行模糊查詢,%一定不要放在最左邊,否則索引失效
- 使用聯合索引,asc和desc不要混用,否則索引失效
- 讓索引在比較表示式中單獨存在,比如 a /2 > 4 優化成a > 4 *2 ,否則索引失效
5. 其他概念
5.1 回表
回表的產生:二級索引中只儲存部分資料,二級索引,聚簇索引,如果需要返回其他列,必然需要再通過聚簇索引去查詢所需要返回的記錄
回表為什麼慢:通過二級索引查詢到的聚簇索引不是有序的,這就造成再通過聚簇索引查詢使用者記錄時不是順序I/O而是隨機I/O,隨機I/O的速度非常慢。所以當返回的資料較多時,可能比全表掃描還慢(全表掃描是順序I/O)
5.2 覆蓋索引
為了徹底告別回表
操作帶來的效能損耗,我們建議:最好在查詢列表裡只包含索引列。也就是覆蓋索引
這也是為什麼鼓勵不適用 *