mysql執行計劃與索引詳解---mysql詳解(二)

文章目錄

mysql執行計劃

注意:mysql各個版本的執行計劃的結果會有區別,需要根據具體的結果來做優化

explain各列釋義

id列

id列的編號是 select 的序列號,有幾個 select 就有幾個id,並且id的順序是按 select 出現的順序增長的。id越大越早執行。

select_type列

select_type 表示對應行是是簡單還是複雜的查詢。
複雜查詢分爲三類:簡單子查詢、派生表(from語句中的子查詢)、union 查詢。

該列的數據類型有:

  • simple:簡單查詢。查詢不包含子查詢和union
  • primary:複雜查詢中最外層的 select
  • subquery:包含在 select 中的子查詢(不在 from 子句中)
  • derived:包含在 from 子句中的子查詢。MySQL會將結果存放在一個臨時表中,也稱爲派生表
  • union:在 union 中的第二個和隨後的 select
  • union result:從 union 臨時表檢索結果的 select

table列

這一列表示 explain 的一行正在訪問哪個表。
當 from 子句中有子查詢時,table列是derivenN 格式,表示當前查詢依賴 id=N 的查詢,於是先執行 id=N 的查詢。當有 union 時,UNION RESULT 的 table 列的值爲 <union1,2>,1和2表示參與 union 的 select 行id。

type列

這一列表示關聯類型或訪問類型,即MySQL決定如何查找表中的行。
依次從最優到最差分別爲:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

type列各數值含義:

  • NULL:mysql能夠在優化階段分解查詢語句,在執行階段用不着再訪問表或索引。例如:在索引列中選取最小值,可以單獨查找索引來完成,不需要在執行時訪問表
  • const, system:mysql能對查詢的某部分進行優化並將其轉化成一個常量(可以看show warnings 的結果)。用於 primary key 或 unique key 的所有列與常數比較時,所以表最多有一個匹配行,讀取1次,速度比較快。
  • eq_ref:primary key 或 unique key 索引的所有部分被連接使用 ,最多隻會返回一條符合條件的記錄。這可能是在 const 之外最好的聯接類型了,簡單的 select 查詢不會出現這種 type。
  • ref:相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前綴,索引要和某個值相比較,可能會找到多個符合條件的行。
  • ref_or_null:類似ref,但是可以搜索值爲NULL的行。
  • index_merge:表示使用了索引合併的優化方法。
  • range:範圍掃描通常出現在 in(), between ,> ,<, >= 等操作中。使用一個索引來檢索給定範圍的行。
  • index:和ALL一樣,不同就是mysql只需掃描索引樹,這通常比ALL快一些。
  • ALL:即全表掃描,意味着mysql需要從頭到尾去查找所需要的行。通常情況下這需要增加索引來進行優化了

possible_keys列

這一列顯示查詢可能使用哪些索引來查找。
explain 時可能出現 possible_keys 有列,而 key 顯示 NULL 的情況,這種情況是因爲表中數據不多,mysql認爲索引對此查詢幫助不大,選擇了全表查詢。
如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查 where 子句看是否可以創造一個適當的索引來提高查詢性能,然後用 explain 查看效果。

key列

這一列顯示mysql實際採用哪個索引來優化對該表的訪問。
如果沒有使用索引,則該列是 NULL。如果想強制mysql使用或忽視possible_keys列中的索引,在查詢中使用 force index、ignore index。

key_len列

這一列顯示了mysql在索引裏使用的字節數,通過這個值可以算出具體使用了索引中的哪些列。

ref列

這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),func,NULL,字段名。

rows列

這一列是mysql估計要讀取並檢測的行數,注意這個不是結果集裏的行數。

Extra列

這一列展示的是額外信息。常見的重要值如下:

  • distinct: 一旦mysql找到了與行相聯合匹配的行,就不再搜索了
  • Using index:查詢的列被索引覆蓋(即覆蓋索引),並且where篩選條件是索引的前導列。這發生在對錶的請求列都是同一索引的部分的時候,返回的列數據只使用了索引中的信息,而沒有再去訪問表中的行記錄。是性能高的表現。
  • Using where:查詢的列未被索引覆蓋,where篩選條件非索引前導列。
  • Using index condition:與user where類似,查詢的列不完全被索引覆蓋,where 條件中是一個前導列的範圍。
  • Using where;Using index:查詢的列被索引覆蓋,並且Where篩選條件是索引列之一但是不是索引的前導列,意味着無法直接通過索引查找符合條件的數據。
  • NULL : 查詢的列未被索引覆蓋,where篩選條件是索引前導列。意味着用到了索引,但是部分字段未被索引覆蓋,必須通過回表來實現。
  • Using temporary:mysql需要創建一張臨時表來處理查詢。出現這種情況一般是要進行優化的,首先是想到用索引來優化。
  • Using filesort:mysql 會對結果使用一個外部索引排序,而不是按索引次序從表裏讀取行。此時mysql會根據聯接類型瀏覽所有符合條件的記錄,並保存排序關鍵字和行指針,然後排序關鍵字並按順序檢索行信息。這種情況下一般也是要考慮使用索引來優化的。

參考文獻:提供了具體例子加以說明


創建索引原則

熟記這些創建索引原則,但具體效果要具體分析。

1、有大量重複值、且經常有範圍查詢( > ,< ,> =,< =)和order by、group by發生的列,可考慮建立羣集索引;

2、經常同時存取多列,且每列都含有重複值可考慮建立組合索引;

3、組合索引要儘量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列;

索引雖有助於提高性能但不是索引越多越好,恰好相反過多的索引會導致系統低效。用戶在表中每加進一個索引,維護索引集合就要做相應的更新工作。

4、表的主鍵、外鍵必須有索引;

5、區分度更高(同值的最少)的字段,建索引;

6、單表數據太少,不適合建索引。例如字典表

7、如果既有單字段索引,又有這幾個字段上的聯合索引,一般可以刪除聯合索引;

8、儘量使用前綴來索引

其實一般情況下我們也不會在字段類型爲TEXT和BLOG類型上加索引。

如果索引字段的值很長,最好使用值的前綴來索引。例如,TEXT和BLOG類型的字段,進行全文檢索會很浪費時間。如果只檢索字段的前面的若干個字符,這樣可以提高檢索速度。

9、爲經常需要排序,分組和聯合操作的字段建立索引。

10、爲常作爲查詢條件的字段建立索引。


查詢語句優化原則

優化方法不止下述提到的這些。有碰到優化方法就要記錄和驗證(一定要驗證,而不是去記,很多博客寫得並不嚴謹)。
以下的方法如果博主有驗證通過了會給完整案例(包括建表、數據量、數據庫執行計劃等信息),如沒有,就是僅供參考而已,優化原則均來自博主同事與網上博客。

這些優化要結合mysql的數據結構,要自己去看explain(執行計劃)。mysql還有他自己的優化,例如:數據量小的時候明明用了這些優化方法還是不走索引。所以要具體問題具體分析。

熟記這些優化原則,但具體效果要具體分析。

1、全值匹配

如果用到了聯合索引,那麼一般情況下,最好是將聯合索引的各字段都用到查詢條件中。

2、最佳左前綴法則

如果索引了多列,要遵守最左前綴法則。指的是查詢從索引的最左前列開始並且不跳過索引中的列。

3、不在索引上做任何的操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而變成全表掃描

4、存儲引擎不能使用索引中範圍條件(>、<、between等範圍查詢)右邊的列

舉例:
name、age、title爲聯合索引,如果是下面的查詢語句,那麼只會用到name、age兩個索引。

SELECT  * FROM employees WHERE name = 'qitian' AND age>18 AND title= '經理'

5、儘量使用覆蓋索引

就是查詢的結果集都爲索引字段,那麼就是覆蓋索引。

6、mysql在使用“不等於”、is null 、 is not null的時候不會使用索引,會進行全表掃描

7、少用or或者in,用or或者in時會導致索引失效

a爲主鍵,b爲索引
select  a, b   from  test  where b  in ( 'x1', 'x2','x3')  

正常情況下,上述sql語句不會走索引。
如果類似的查詢語句必須走索引的話
可以考慮用union來聯結,分開查詢就可以走索引了。

select  a, b  from  test    where  b ='x1'
union
select  a, b  from  test    where  b ='x2'
union
select  a, b  from  test    where  b ='x3'

8、字符串不加單引號導致索引失效。

9、當取出的數據超過全表數據的20%時,不會使用索引

10、使用like時注意:

不使用索引:
like ‘%L%’
使用索引:
like ‘L%’

11、如果使用數字作爲字符,則數字需要加引號,否則mysql會自動在列上加數據類型轉換函數

不使用索引
where mobile=18868886888
使用索引
where mobile=’18868886888’

12、字段加運算符不會使用索引。所以儘量把運算放在數值上

不使用索引:
SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE AMOUNT + 3000 >5000;
使用索引:
SELECT ACCOUNT_NAME, AMOUNT FROM TRANSACTION WHERE AMOUNT > 2000 ;

13、ORDER BY 子句只在以下的條件下使用索引:

ORDER BY中所有的列必須包含在相同的索引中並保持在索引中的排列順序.
ORDER BY中不能既有ASC也有DESC
例如:
alter table test1 add index(a,b);
alter table test1 add index©;

不使用索引:
select * from test1 order by a,c; 不在一個索引中
select * from test1 order by b; 沒有出現組合索引的第一列
select * from test1 order by a asc, b desc; 混合ASC和DESC
select * from test1 where a=1 order by c; where和order by用的不是同一個索引,where使用索引,order by不使用。

使用索引:
select * from test1 order by a,b;
select * from test1 order where a=1 order by b;
select * from test1 order where a=1 order by a,b;
select * from test1 order by a desc, b desc;
select * from test1 where c=1 order by c;

14、只要能滿足你的需求,應儘可能使用更小的數據類型:例如使用MEDIUMINT代替INT

15、從 PROCEDURE ANALYSE() 取得建議

PROCEDURE ANALYSE() 會讓 MySQL 幫你去分析你的字段和其實際的數據,並會給你一些有用的建議。只有表中有實際的數據,這些建議纔會變得有用,因爲要做一些大的決定是需要有數據作爲基礎的。

表中需要有數據,這樣mysql纔好給出建議,結果集的最後一列就是mysql認爲應該改用的數據類型建議。
在這裏插入圖片描述

16、join 語法,儘量將小的表放在前面,在需要on的字段上,數據類型保持一致,並設置對應的索引,否則MySQL無法使用索引來join查詢

17、在大表上做大量更新時,如果會鎖全表,則需要拆分執行,避免長時間鎖住表,導致其他請求積累太多InnoDB 支持行鎖,但前提是Where子句需要建立索引,沒有索引也一樣是鎖全表

18、永遠用小結果集驅動大的結果集,小數據集的表先執行。

19、MySQL支持兩種方式的排序filesort和index,Using index 是指MySQL掃描索引本身完成排序。index效率高,filesort效率低。

20、 order by 滿足兩種情況會使用Using index。

  1. order by語句使用索引最左前列。
  2. 使用Where子句與order by 子句條件列組合滿足索引最左前列

21、group by 與order by 很類似,其實質是先排序後分組,遵照索引創建順序的最佳左前綴法則。注意Where高於having,能寫在where中的限定條件就不要去having限定了。

劃重點(∩_∩)



本人程序媛一枚,因爲離港澳較近,週末兼職港澳人肉代購。

歡迎各位大佬添加本人微信,還會經常有點贊活動送價值不菲的小禮品哦。

即使現在不需要代購,等以後有了女(男)朋友、有了寶寶就肯定會需要的嘍。

動動手指頭,掃碼一下,就當是對本博文的支持嘛,也是對一個平凡、勤勞、勇敢、秀外慧中等等優點的程序媛莫大的支持哈。
在這裏插入圖片描述

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