1. 程式人生 > 其它 >知識筆記---4.索引失效及查詢優化

知識筆記---4.索引失效及查詢優化

1. 索引失效

(1)全值匹配的情況
(2)最佳左字首法則:如果索引了多列,要遵守最左字首法則。指的是查詢從索引的最左前列開始並且不跳過索引中的列
(3)不在索引列上做任何操作(計算、函式、型別轉換),會導致索引失效而轉向全表掃描
(4)儲存引擎不能使用索引中範圍條件右邊的列
(5)儘量使用覆蓋索引,減少select *
(6)mysql在使用!=的時候無法使用索引會導致全表掃描
(7)is not null也無法使用索引,但是is null是可以使用索引的
(8)like以萬用字元開頭時,mysql索引失效會變成全表掃描
(9)字串不加單引號索引失效
(10)少用or,用它來連線時索引會失效
(11)where子句中如果出現索引的範圍查詢會導致order by索引失效

補充

回表

select * from table where name = zhansan;
第一次查詢name的B+樹,根據name獲取到主鍵id,然後根據id去id的B+樹找到記錄,這個回表過程會導致IO次數變多。

覆蓋索引

select id, name from table where name = zhansan;
在進行檢索時,直接根據name去name的B+樹獲取到id,name兩列的值,不需要回表,效率高,應該儘可能多的使用索引覆蓋來替代回表,所以有時候,在複雜的sql中,可以考慮將不相關的列都設定為索引列。

最左匹配

有一個表:id,name,age,gender(id是主鍵,name,age是聯合索引)
select * from table where name=?           # 符合
select * from table where name=? and age=? # 符合
select * from table where age=? = name=?   # 優化器會優化,使其符合最左匹配
select * from table where age=?            # 不符合

索引下推

select * from table where name=? and age=?
在沒有索引下推之前,先根據name去儲存引擎中拉取符合結構的資料,返回到server層,在server層中對age的條件進行過濾
有了索引下推之後,根據name,age兩個條件直接從儲存引擎中拉去結果,不需要再server層做條件過濾
mysql5.7版本之後預設開啟

2. 查詢優化

1.小表驅動大表

當A表的資料集小於B表的資料集的時候,用in優於exists
select * from A where id in (select id from B)
等價於
select id from B
select * from A where A.id = B.id


當B表的資料集小於A表的資料集的時候,用exists優於in
select * from A where exists (select 1 from B where B.id = A.id)
等價於
select * from A
select * from B where B.id = A.id

2.order by關鍵字優化

  1. MySQL支援二種方式的排序,FileSort和Index。
    Index效率高,指MySQL掃描索引本身完成排序。FileSort方式效率較低。
  2. 儘可能在索引列上完成排序操作,遵照索引鍵的最佳做字首
  3. ORDER BY滿足兩情況,會使用Index方式排序
    ORDER BY 語句使用索引最左前列
    使用Where子句與Order BY子句條件列組合滿足索引最左前列
設a,b,c為索引

order by能使用索引最左字首
-ORDER BY a
-ORDER BY a, b
-ORDER BY a, b, c
-ORDER BY a desc, b desc, c desc

如果WHERE使用索引的最左字首定義為常量,則order by能使用索引
where a = const order by b,c
where a = const and b = const order by c
where a = const and b > const order by b,c

不能使用索引進行排序
order by a asc, b desc, c desc -- 排序不一致
where g = const order by b, c  -- 丟失a索引
where a = const order by c     -- 丟失b索引
where a = const order by a, d  -- d不是索引的一部分
where a in (...) order by b, c -- 對於排序來說,多個相等條件也是範圍查詢
如果不在索引列上,filesort有兩種演算法
1.雙路排序(又叫回表排序模式)

先根據相應的條件取出相應的排序欄位和可以直接定位行資料的行ID,然後在sort buffer中進行排序,排序完後需要再次取回其它需要的欄位

舉個例子,下面有一段sql:
select * from user where name="自由的辣條" order by age
1.從索引 name 找到第一個滿足 name = ‘自由的辣條’ 的主鍵id
2.根據主鍵 id 取出整行,把排序欄位 age 和主鍵 id 這兩個欄位放到 sort buffer(排序快取) 中
3.從索引 name 取下一個滿足 name = ‘自由的辣條’ 記錄的主鍵 id
4.重複 1、2 直到不滿足 name = ‘自由的辣條’
5.對sort_buffer中的欄位 age 和主鍵 id 按照欄位 age進行排序
6.遍歷排序好的 id 和欄位 age ,按照 id 的值回到原表中取出 所有欄位的值返回給客戶端
2.單路排序

結論及引申出的問題:
結論:由於單路是後出的,總體而言好過雙路
問題:在sort_buffer中,方法B比方法A要多佔用很多空間,因為方法B是把所有欄位都取出, 所以有可能取出的資料的總大小超出了sort_buffer的容量,導致每次只能取sort_buffer容量大小的資料,進行排序(建立tmp檔案,多路合併),排完再取取sort_buffer容量大小,再排……從而多次I/O。本來想省一次I/O操作,反而導致了大量的I/O操作,反而得不償失。