MySQL優化(5):索引失效分析、in與exists使用場合

1、索引失效的狀況

  前文說起過能夠經過explain的possible_keys、key屬性判斷索引是否失效,key若是爲null,多是索引沒建,也多是索引失效,下面列舉一些會使索引失效的狀況。mysql

一、全值匹配:順序、個數與索引一致算法

二、最佳左前綴法則:查詢從索引的最左前列開始而且不跳過索引中的列,中間跳過的值,後面的索引會失效sql

三、索引列上作了操做(計算、函數、自動或手動類型轉換),會致使索引失效而轉向全表掃描函數

四、存儲引擎不能使用索引中範圍條件右邊的列優化

  

  name字段用於查找,age>11也用到了,但着重用於排序,pos則沒用到索引spa

五、儘可能使用覆蓋索引(索引列和查詢列一致),減小select *3d

  using where是在表裏檢索,using index會直接從索引裏檢索指針

   

  這裏也是範圍檢索,但與上面不一樣的是這裏從索引裏獲取數據,沒有用到agecode

   

六、mysql在使用不等於(!= 或 <>)時沒法使用索引blog

   

七、is null,is not null也沒法使用索引

八、like以通配符開頭(‘%abc..’)也會致使索引失效

  經過覆蓋索引能夠解決like '%字符串%'索引失效的問題

  例:假設以name,age字段建索引

create index idx_user_nameAge on tb_user(name,age);

  查詢字段只要有一個和覆蓋索引沾邊就行

   

  

  但若是有超過索引的部分,索引就用不上了,因此用select * 就不能使用覆蓋索引

   

九、字符串不加單引號,該字段之後的索引失效

十、少用or,用它來鏈接時會索引失效

   

十一、少數據值的列也不該該增長索引,只有兩種狀況,且平均分佈,加了索引反而下降速度

十二、range的包含範圍有必定的閾值,超過會進行全文掃描

 2、in與exists使用場合

  堅持小表驅動大表的原則

in:當B表的數據集必須小於A表的數據集時,in優於exists 

select * from A where id in (select id from B) #等價於:   for select id from B   for select * from A where A.id = B.id

exists:當A表的數據集小於B表的數據集時,exists優於in

  將主查詢A的數據,放到子查詢B中作條件驗證,根據驗證結果(true或false)來決定主查詢的數據是否保留

  子查詢也能夠用條件表達式、其餘子查詢或join來替代,何種最優需具體問題具體分析

select * from A where exists (select 1 from B where B.id = A.id) #等價於 for select * from A for select * from B where B.id = A.id #A表與B表的ID字段應創建索引

3、對Order By的優化

一、用order by子句的重點是是否會產生filesort。建索引時已經排好序,因此order by的順序和索引最好一致,避免再一次排序。    

    

  所建的索引默認升序,一升序一降序會產生內排序

   

二、狀態最好是using index,讓mysql經過掃描索引自己完成排序。

  能使用index方式排序的狀況:order by語句使用索引最左前列,或where子句與order子句條件組合知足索引最左前列。

 (1)order by語句使用索引最左前列,order by後字段同爲asc或desc都行

    

 (2)加上where子句的條件與order by子句條件列組合知足索引最左前列

   

 (3)不能使用索引的狀況

   

   假如以category_id、comments、views的順序建索引

  

三、filesort的兩種算法

 (1)雙路排序:兩次掃描磁盤(讀取行指針和order by列,對他們進行排序,而後掃描已排好序的列表,從新列表讀取數據輸出)。

 (2)單路排序:mysql4.1版本後,從磁盤讀取查詢須要的全部列,按order by列在buffer對它們排序,而後掃描排序後的列表輸出,只讀取一次數據,且把隨機IO變爲順序IO,但會使用更多空間,由於它把每一行都保存在內存中。

    單路排序存在的問題:

    由於要把全部字段取出,可能要取出的大小超出sort_buffer容量,致使每次只能取sort_buffer容量大小的數據進行排序(建立tmp文件,多路合併),排完再取sort_buffer容量大小的數據,反而會致使更多I/O操做。

四、order by優化策略:

 (1)單路多路算法的數據都有可能超過sort_buffer_size,超出後會建tmp文件進行合併排序,致使屢次I/O,能夠根據系統能力增大sort_buffer_size參數設置

 (2)增大max_length_for_sort_data參數,會增長用單路排序的機率,但若是設太大,也會更容易使數據超過sort_buffer_size,當query的字段大小總和小於max_length_for_sort_data且排序字段不是text/blob類型時,纔會用單路排序,不然仍是用多路排序。

 (3)order by時不要用select *,只select須要的字段,多餘的字段會佔用sort_buffer的內存

五、group by:  

  適用order by原則,實質先排序後分組,遵照索引建的最佳左前綴,使用不當會產生臨時表。

   

  當沒法使用索引列,增大max_length_for_sort_data和sort_buffer_size參數設置。能在where的條件就不放在having裏。

4、案例,其餘注意點

  假如以c1,c2,c3,c4的順序創建索引

一、對於常量類型,查詢優化器會自動調優SQL,順序不影響

   

二、範圍以後全失效,但查詢優化器會先常量類型自動調優,c3被調前,c4後的失效,但c4是最後一個了,因此仍用到4個。以上的例子中間並無斷

   

三、都只用到了c1,c2,第三條語句沒法使用到索引排序,因此mysql內部本身進行了一次排序(前兩個c3沒用到查找,但用到了排序,因此無using filesort,只是沒有記錄到key_len裏)

   

四、order by不按索引順序會出現using filesort,原本照理第一個按order by c3,c2排序會出現filesort,可是前面已經有c2=‘a2’的條件,c2已是常量值,因此c2其實不用排序

   

 5、多表鏈接在從表加索引能夠提升速度

案例1:兩錶鏈接的狀況,多表鏈接時在主表仍是從表建索引的問題

  如未使用索引的狀況

   

  左鏈接把索引建在從表的關聯字段比較好,主表必定會有,從表纔是檢索的關鍵

   

案例2:三表關聯要建在哪些字段上

  沒建索引的時候

   

  在第2、三個從表的關聯字段加索引

ALTER TABLE `phone` ADD INDEX z(`card`); ALTER TABLE `book` ADD INDEX Y(`card`); 

    

結論:

  (1)join語句中被驅動表上join條件字段加索引能夠提升效率;

  (2)當沒法保證被驅動表的join條件字段被索引且內存資源充足的前提下,不要太吝嗇JoinBuffer的設置。

相關文章
相關標籤/搜索