前文提及過可以通過explain的possible_keys、key屬性判斷索引是否失效,key如果為null,可能是索引沒建,也可能是索引失效,下面列舉一些會使索引失效的情況。
1、全值匹配:順序、個數與索引一致
2、最佳左前綴法則:查詢從索引的最左前列開始並且不跳過索引中的列,中間跳過的值,后面的索引會失效
3、索引列上做了操作(計算、函數、自動或手動類型轉換),會導致索引失效而轉向全表掃描
4、存儲引擎不能使用索引中范圍條件右邊的列
name字段用於查找,age>11也用到了,但着重用於排序,pos則沒用到索引
5、盡量使用覆蓋索引(索引列和查詢列一致),減少select *
using where是在表里檢索,using index會直接從索引里檢索
這里也是范圍檢索,但與上面不同的是這里從索引里獲取數據,沒有用到age
6、mysql在使用不等於(!= 或 <>)時無法使用索引
7、is null,is not null也無法使用索引
8、like以通配符開頭(‘%abc..’)也會導致索引失效
通過覆蓋索引可以解決like '%字符串%'索引失效的問題
例:假設以name,age字段建索引
查詢字段只要有一個和覆蓋索引沾邊就行
但如果有超過索引的部分,索引就用不上了,所以用select * 就不能使用覆蓋索引
9、字符串不加單引號,該字段以后的索引失效
10、少用or,用它來連接時會索引失效
11、少數據值的列也不應該增加索引,只有兩種情況,且平均分布,加了索引反而降低速度
12、range的包含范圍有一定的閾值,超過會進行全文掃描
堅持小表驅動大表的原則
in:當B表的數據集必須小於A表的數據集時,in優於exists
exists:當A表的數據集小於B表的數據集時,exists優於in
將主查詢A的數據,放到子查詢B中做條件驗證,根據驗證結果(true或false)來決定主查詢的數據是否保留
子查詢也可以用條件表達式、其他子查詢或join來替代,何種最優需具體問題具體分析
1、用order by子句的重點是是否會產生filesort。建索引時已經排好序,所以order by的順序和索引最好一致,避免再一次排序。
所建的索引默認升序,一升序一降序會產生內排序
2、狀態最好是using index,讓mysql通過掃描索引本身完成排序。
能使用index方式排序的情況:order by語句使用索引最左前列,或where子句與order子句條件組合滿足索引最左前列。
(1)order by語句使用索引最左前列,order by后字段同為asc或desc都行
(2)加上where子句的條件與order by子句條件列組合滿足索引最左前列
(3)不能使用索引的情況
假如以category_id、comments、views的順序建索引
3、filesort的兩種算法
(1)雙路排序:兩次掃描磁盤(讀取行指針和order by列,對他們進行排序,然后掃描已排好序的列表,重新列表讀取數據輸出)。
(2)單路排序:mysql4.1版本后,從磁盤讀取查詢需要的所有列,按order by列在buffer對它們排序,然后掃描排序后的列表輸出,只讀取一次數據,且把隨機IO變為順序IO,但會使用更多空間,因為它把每一行都保存在內存中。
單路排序存在的問題:
因為要把所有字段取出,可能要取出的大小超出sort_buffer容量,導致每次只能取sort_buffer容量大小的數據進行排序(創建tmp文件,多路合並),排完再取sort_buffer容量大小的數據,反而會導致更多I/O操作。
4、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的內存。
5、group by:
適用order by原則,實質先排序后分組,遵守索引建的最佳左前綴,使用不當會產生臨時表。
當無法使用索引列,增大max_length_for_sort_data和sort_buffer_size參數設置。能在where的條件就不放在having里。
假如以c1,c2,c3,c4的順序建立索引
1、對於常量類型,查詢優化器會自動調優SQL,順序不影響
2、范圍之后全失效,但查詢優化器會先常量類型自動調優,c3被調前,c4后的失效,但c4是最后一個了,所以仍用到4個。以上的例子中間並沒有斷
3、都只用到了c1,c2,第三條語句無法使用到索引排序,所以mysql內部自己進行了一次排序(前兩個c3沒用到查找,但用到了排序,所以無using filesort,只是沒有記錄到key_len里)
4、order by不按索引順序會出現using filesort,本來照理第一個按order by c3,c2排序會出現filesort,但是前面已經有c2=‘a2’的條件,c2已經是常量值,所以c2其實不用排序
案例1:兩表連接的情況,多表連接時在主表還是從表建索引的問題
如未使用索引的情況
左連接把索引建在從表的關聯字段比較好,主表一定會有,從表才是檢索的關鍵
案例2:三表關聯要建在哪些字段上
沒建索引的時候
在第二、三個從表的關聯字段加索引
結論:
(1)join語句中被驅動表上join條件字段加索引可以提高效率;
(2)當無法保證被驅動表的join條件字段被索引且內存資源充足的前提下,不要太吝嗇JoinBuffer的設置。
原文 :https://www.cnblogs.com/zjxiang/p/9160810.html