面試官:不會sql優化?出門右轉順便帶上門,謝謝


導讀

作為一個后端程序員,數據庫這個東西是繞不開的,特別是寫sql的能力,如果您參加過多次面試,那么一定會從面試復盤中發現面試官總是會考察到sql優化這個東西。

我在之前的多次面試中最常遇到的一個問題的sql優化,不論是大廠還是小廠。但我之前沒有詳細去了解過這些東西啊,我就瞎雞兒吹了,畢竟我也干過兩三年的crud,sql還是寫過不少的,也遇到過一些特別長的sql,執行時間特別長的sql,所以以前經常犧牲午睡時間給客戶出報表還是有點效果的,mmp的。

我是這樣說的:Sql優化,首先就是看sql的執行計划,然后按照執行計划對應的執行修改,比如該建索引建索引,然后就balabala....

其實老子之前壓根就沒學過怎么看執行計划,純靠這么些年寫sql的經驗瞎雞兒吹。這也是上個月開始看MySqL,才學會看,那今天就現學現賣,給您們展示兩下子。

SQL執行計划(以MySQL為例)

1、如何查看sql的執行計划

在需要執行的查詢SQL前添加一個關鍵字“EXPLAIN”

 

從上圖可以看到,執行計划共有12字段,先來簡便看每一列的作用:

字段解釋idselect查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序select_type查詢類型table訪問到的表partitions匹配的分區type訪問類型possible_keys有可能會使用到的索引key實際使用到的索引,如果為NULL,則沒有使用索引key_len索引中使用的字節數,可通過該列計算查詢中使用的索引長度ref顯示索引的哪一列被使用了rows估算找到所需數據需讀取的行數filtered查詢的表行占表的百分比extra包含不適合在其他列展示但異常重要的信息,比如是使用索引排序還是文件排序

2、EXPLAIN中的列

(1)id

1、標識select所屬的行,sql語句中有多少個select就有多少個id,並且id的順序是按照select出現的順序增長的

2、id越大,越先執行

3、id相同,從上往下執行

4、id為NUll的最后執行

例如:(1)id相同,從上往下依次執行

explain 
select * from student,class,class_student;

  

 

(2)id不同,id越大執行優先級越高

explain 
select s.id,s.name,(select 1 from class) from student s;

  

 

(3)id相同又不同,id越大越先執行,id相同從上往下執行

explain 
select id,name from student where id <5 union select s.id,s.
name from student s,class_student cs where cs.stu_id = s.id and cs.class_id = 4;

  

 

(2) select_type

顯示對應行是簡單還是復雜select,SIMPLE值表明沒有子查詢或Union,如果有子查詢,那么最外層標記為Primary

(1)SUBQUERY 包含在select字段中的子查詢,不在From語句中 例如:

explain 
select id,name,(select class_id from class_student) from student;

  

 

(2)DERIVED 包含在From中的子查詢,MySQL會遞歸執行並將結果放在一個臨時表中,成為派生表,從子查詢中派生出來的。

(3)UNION 在UNION中的第二個和隨后的select被標記為UNION。第一個select被標記為外查詢來執行,如果UNION被From子句中的子查詢包含,那么它的第一個Select會被標記為DERIVED。

explain 
     select id,name from student where id>5
     union
     select id,name from student where id>15;

  

 

UNION被包含在From子句中的示例:

explain
     select * from (
     select id,name from student where id>15
     union
     select id,name from student where id<4
     ) a;

  

 

(4)UNION RESULT 用來從UNION的匿名臨時表檢索結果的select被標記為UNION RESULT。上例中可以看到

(5)DEPENDENT select依賴於外層查詢中發現的數據。

explain      select s.id,s.name,(select class_id from class_student cs where cs.stu_id = s.id) from student s; 

 

(6)UNCACHEABLE select中的某些特性阻止結果被緩存在一個Item_cache中。

(3) table

顯示當前行的數據來自於哪一張表

(4)type

訪問類型,結果值從好到壞依次是:NULL>system>const>eq_ref>ref>range>index>ALL

一般來說,保證查詢至少能到達range級別,最好能達到ref。

(1)system 表中只有一行數據(系統表)

(2)const 通過索引一次就能找到的數據,比如primary key 和union key,主鍵在where條件中,就能將查詢轉換成一個常量。比如:student表中id是主鍵

explain
   select * from student where id = 1;

  

 

(3)eq_ref 唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描。

explain
   select * from student s left join (select * from class_student where stu_id > 10)cs on cs.stu_id = s.id where cs.class_id = 4;

  

 

(4)ref 非唯一性索引掃描,返回匹配某個單獨值得所有行 比如:student表中的age是一個普通索引

explain 
select * from student where age = 20;

  

 

(5)range

1、只檢索給定范圍的行,使用一個索引來選擇行,key列顯示使用了哪個索引

2、一般就是where條件中出現“>”、“<”、“between”、“in”等條件

3、這種范圍掃描索引掃描比全表掃描要好,因為它只需要開始於索引的某一點,而結束語另一點,不用掃描全部索引。

例如:

explain
select * from student where id > 5;

  

 

(6) All 全表掃描,不使用任何條件或索引。比如:student表中score字段是沒有設置索引的。

 

(5)possible_keys

可能會使用到的key

(6)key

實際使用到的key

(7)key_len

索引中使用的字節數,可通過該列計算出使用的是哪些列,長度越短越好。顯示的是索引字段的最大可能長度,並非實際使用長度,根據表定義計算而來,不是通過表內檢索而來。

需要注意的是:1、char字段一個字符在utf8編碼下最多占3個字節,可變長字段需要額外的兩個字節記錄長度,外加需要存入一個null值,一個null是一個字節 2、復合索引有最左前綴的特性,如果復合索引能全部使用上,則是復合索引字段的索引長度之和,這也可以用來判定復合索引是否部分使用,還是全部使用。

比如:student表的id是int類型,四個字節,所以key_len是4

explain
select * from student where id > 5;

  

 

name字段類型是varchar(20),所以ken_len=20*3+2+1=63

EXPLAIN
  select * from student where name = '張三';

  

 

(8)ref

顯示索引的哪一列被使用了,如果可能的話,是一個常數。哪些列或者常量被用於查找索引列上的值。

explain
select * from student s,class_student cs where cs.stu_id=s.id and cs.class_id = 4;

  

 

從第二行可知,使用了student表中的主鍵查詢,ken_len為4 ref為test.cs.stu_id表明使用了cs表中的stu_id字段。

(9) rows

根據表統計信息及索引選用情況,大致估算出找到所需的記錄需要讀取的行數。

(10)extra

值描述Using filesort說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中無法利用索引完成的排序操作稱為"文件排序"Using temporary使了用臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序 order by 和分組查詢 group by。Using index表示相應的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的數據行,效率不錯!  如果同時出現using where,表明索引被用來執行索引鍵值的查找;   如果沒有同時出現using where,表明索引用來讀取數據而非執行查找動作Using where使用了where條件Using join buffer使用了連接緩存impossible wherewhere子句的值總是false,不能用來獲取任何元素distinct一單mysql找到了與形相聯合匹配的行,就不在搜索了

注意:當在Extra列出現了Using filesort時候,就說明可以建立相應的索引進行排序優化查詢了。

下面是一個完整的思維導圖:

 

===============================

我是Liusy,一個喜歡健身的程序員。

獲取更多干貨以及最新消息,請關注公眾號:上古偽神

如果對您有幫助,點個關注就是對我最大的支持!!!

結尾小驚喜:公眾號回復“MySQL”,送您一個MySQL的整體思維導圖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM