一、何謂索引?
索引,簡單說,就是排好序,查找的快的一種資料結構;
二、sql為何慢?
1、查詢語句寫的爛;
2、索引失效:(單值、複合)
3、關聯查詢太多
4、伺服器調優(緩沖、線程數)
三、索引優勢與劣勢;
優勢:提高檢索效率,降低IO成本;降低資料的排序成本,降低CPU的消耗;
劣勢:索引也是一張表,該表儲存了主鍵與索引字段,并指向實體表的記錄,是以索引也需要占用空間,其次,在更新表時,不僅要更新資料,還要更新索引;
四、索引分類?
單值索引:隻包含一個列;
唯一索引:索引列的值必須時唯一的,不過可以有空值;
複合索引:一個索引包含多個列;
五、主角——explain
1、是什麼?
使用explain可以模拟優化器執行sql語句,進而知道mysql是如何執行sql語句的
2、能幹嘛?
表的讀取順序、資料讀取操作的操作類型、那些索引可以使用、那些索引被實際使用、表之間的引用、每張表有多少行被優化器查詢
3、怎麼用?
explain + sql
4、長什麼樣?
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-UCwcFue8-1595842967023)(/Applications/Typora.app/Contents/Resources/TypeMark/Docs/img/WechatIMG4.jpeg)]
id: select 查詢的編号,表示查詢順序:
id相同,順序執行,由上到下;
id不同,如果是自查詢,ID的序号會增加,ID值越大,優先級越高,越先被執行
select_type:有哪些?
simple、primary、subquery、derived、union、union result;
作用?
simple:簡單查詢,不包含任何自查詢和關聯查詢;
EXPLAIN SELECT * from PROJECT where id = 1
primary:查詢中包含任何複雜的子部分,最外層查詢則被标記為primary
EXPLAIN SELECT * from BUILDING b LEFT join (select building_id,sum(UNOCCUPIED_AREA) as area from RENTAL_UNIT ru group by building_id having area > 40000 ) r on r.building_id = b.ID where b.ID > 13231
subquery:在select或者where字句中包含的複雜子查詢
EXPLAIN SELECT (select Id from PROJECT ) from DUAL
EXPLAIN select * from DEMAND_SITE_VISIT where CREATE_TIME > (SELECT MAX(CREATE_TIME) from DEMAND_FOLLOW_LOG )
derived:在from中包含子查詢被标記為derived,mysql會遞歸執行這些子查詢,把結果放在臨時表裡面;
EXPLAIN SELECT * from BUILDING b LEFT join (select building_id,sum(UNOCCUPIED_AREA) as area from RENTAL_UNIT ru group by building_id having area > 40000 )r on r.building_id = b.ID
where b.ID > 13231
union:如果第二個select出現在union後,則會被标記為union,如果union包含在from子句的子查詢中,則外層的select被标記為derived;
explain SELECT ID FROM DEMAND UNION select REMARK from DEMAND_FOLLOW_LOG
union result:從union結果中擷取的select
explain SELECT ID FROM DEMAND UNION select REMARK from DEMAND_FOLLOW_LOG
table:顯示操作的是哪一張表;
type:system>const>eq_ref>ref>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>all
System:表中隻有一條記錄,這是const的執行個體,可以忽略
explain select * from (select id from PROJECT where id = 15) a
const:通過索引一次就可以找到了,一般出現在primary key或者唯一索引的地方,是以快得很;
explain select * from PROJECT where id = 15
eq_ref:簡單說,用于連結清單查詢,按照聯表的主鍵或者唯一建删除,讀取本表和關聯聯表中的每行組合成的一行,eq_ref可以使用=比對索引的列,比較值可以是常量或者使用此表之前讀取的表中的列的表達式,當連接配接使用索 引的所有部分時,索引是主鍵或唯一非null索引時,将使用該值;
explain SELECT * FROM PROJECT p,BUILDING b where p.ID = b.PROJECT_ID and p.CITY_CODE = '310100’
ref:非唯一性索引掃描,傳回某個比對單獨值的所有行,本質上也是一種索引通路,它傳回所有比對某個單獨值的行,然而,它可能會找到多個符合條件的行,是以他應該屬于查找和掃描的混合體;
EXPLAIN SELECT * from FUNNEL_REPORT where UTM_SOURCE = 'baidu’;
explain SELECT * from PROJECT p LEFT join BUILDING b on p.ID = b.PROJECT_ID
range:隻檢索給定範圍的行,使用一個索引來選擇行,key列顯示使用了哪個索引,一般就是在where語句中出現了between、<、>、in等查詢語句,這種範圍掃描 索引比全表掃描要好,因為它隻需要開始于索引的某一點,而結束于另一點;
explain SELECT * from PROJECT where id > 1890
Index merge:where子句包含多個條件(and 或者or連接配接),mysql在5.1開始,開始了index merge,其實就是對多個索引列進行條件掃描,然後将各個結果進行合并;
index:full index scan,index與ALL差別為index類型隻周遊索引樹,這通常比ALL快,因為索引檔案通常比資料檔案小;
all:full table scan,将便利全表以找到比對的行
一般來說,要保證查詢至少達到range級别,最好能達到ref;
possible_keys:顯示可能應用在這張表中的索引,一個或多個,查詢涉及到字段上若存在的索引,則該索引将被列出,但不一定被查詢實際用到;
key:實際使用的索引,如果為null,則沒有使用索引,查詢中若使用了覆寫索引,則該索引和查詢的select字段重疊;
explain SELECT MOBILE_NO,STATUS from CONTACT where NAME = ‘f123dfff’ and
TYPE
=4
key_len:表示索引中使用的位元組數,可通過該列計算查詢中使用的索引長度,在不損失精确性的情況下,長度越短越好,顯示的值為索引字段的最大可能長度,是一個常數,并非實際使用長度,即key_len是根據表定義計算而得,不是通過表内檢索出的;(可計算 default null:1位元組、varchar:2位元組、tinyint:1位元組)
ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數,那些列或常量被用于查找索引列上的值;
rows:根據表統計資訊及索引選用的情況,大緻估算出找到所需的記錄需要讀取的行數;
extra:
using filesort:說明mysql會對資料使用一個外部的索引排序,而不是按照表内的索引順序進行讀取,mysql中無法利用索引完成的排序操作稱為檔案排序;
explain SELECT MOBILE_NO,STATUS from CONTACT where NAME = ‘f123dfff’ and type = 4 order by MOBILE_NO
using temporary:使用了臨時表儲存中間結果,mysql在對查詢結果排序時使用臨時表,常見于排序orderby和分組group by;
explain SELECT * from CONTACT group by
TYPE
using index:表示相應的select操作中使用了覆寫索引,避免通路了表的資料行,效率不錯,如果同時出現using where,表明索引被用來執行索引鍵值的查找,如果沒有同時出現using where,表明索引用來讀取資料而非執行查找動作;
explain SELECT MOBILE_NO,STATUS from CONTACT where NAME = ‘f123dfff’ and type = 4 order by MOBILE_NO DESC
using where:表明使用了where過濾;
explain SELECT MOBILE_NO,STATUS from CONTACT where NAME = ‘f123dfff’ and type = 4 order by MOBILE_NO DESC
using join buffer:使用了連接配接緩存;隻有當join類型為all,index,range後者是index_merge的時候才會使用join buffer;
impossible where :where子句的值總是false,不能用來擷取仍和元組;
explain SELECT MOBILE_NO,STATUS from CONTACT where 1=2
select table optimized away:在沒有groupby子句的情況下,基于索引優化min/max操作或者對于myisam存儲引擎優化count(*)操作,不必等到執行階段再進行計算,查詢計劃生成的階段即完成優化;
distinct:優化distinct操作,在找到第一比對的元組後即停止找同樣值的動作;
索引失效與優化:
1、全部比對最佳
2、最佳最字首法則(如果索引了多列,要遵守最左字首法則,指的是查詢從索引的最左前列開始并且不跳過索引中的列)
3、不在索引列上做任何操作(計算、函數、類型轉換)
4、(避免select *)盡量使用覆寫索引
5、存儲引擎不能使用索引中範圍條件右邊的列
6、mysql在使用不等于的時候無法使用索引會導緻全表掃描
7、is null,is not null也無法使用索引
8、like以通配符開頭(“%abc”)mysql索引失效會變成全表掃描的操作
9、字元串不加單引号索引會失效
10、少用or,用它來連接配接時會索引失效
一般性的建議:
對于單值索引,盡量選擇針對目前的query過濾性更好的索引;
在選擇組合索引的時候,目前query中過濾性最好的字段在索引字段順序中,位置越靠前越好;
在選擇組合索引的時候,盡量選擇可以能夠包含目前query中的where字句中更多字段的索引;
盡可能通過分析統計資訊和調整query的寫法來達到選擇合适索引的目的;
查詢截取分析:
查詢優化:
永遠小表驅動大表
order by關鍵字優化:盡量使用index方式排序,避免使用filesort方式排序;
盡可能在索引列上完成排序操作,遵照索引建立最佳左字首;
如果不在索引列上,filesort有兩種算法,mysql就要啟動雙路排序和單路排序;
雙路排序:mysql4.1之前使用雙路排序,字面意思是兩次掃描磁盤,最終得到資料,讀取行指針和orderby列,對他們進行排序,然後掃描已經排序好的清單,按照清單中的值重新從清單中讀取對應的資料輸出,從磁盤取排序字段,在buffer進行排序,再從磁盤取其他字段;
單路排序:從磁盤讀取查詢需要的所有列,按照orderby列在buffer對他們進行排序,然後掃描排序後的清單進行輸出;它的效率更快一些,避免了第二次讀取資料,并且把随機IO變成了順序IO,但是它會使用更多的空間;
優化政策:
增大sort_buffer_size參數的設定;
增大max_length_for_sort_data參數的設定;
groupby關鍵字的優化:
groupby實質是先排序後進行分組,遵照索引建立的最佳左字首;
當無法使用索引列,增大max_length_for_sort_data和sort_buffer_size參數的設定;
where高于having,能寫where限定的條件就不要去having限定了;
執行個體:
1、SELECT COUNT(DISTINCT a.ID) AS COUNT
FROM PROJECT a
LEFT JOIN LEADS d ON d.PROJECT_ID = a.ID
LEFT JOIN PROJECT_COMPANY_ASSN pc ON pc.PROJECT_ID = a.ID
LEFT JOIN OWNER c ON c.COMPANY_ID = pc.COMPANY_ID AND pc.STATUS = 1 AND pc.TYPE = 3
WHERE d.STATUS != 12 AND a.STATUS in ( 0 ) AND d.STATUS = 7
2、SELECT
COUNT(1) AS VIEW_COUNT,
pd.PROJECT_ID
FROM PROJECT_DETAIL_VIEW_LOG pd
INNER JOIN PROJECT p
ON p.ID = pd.PROJECT_ID
WHERE p.PROVINCE_CODE = ‘320281’
OR p.CITY_CODE=‘320281’
OR p.DISTRICT_CODE=‘320281’
GROUP BY pd.PROJECT_ID
ORDER BY VIEW_COUNT DESC
LIMIT 0,10