1. 程式人生 > >mysq order by 不走索引問題

mysq order by 不走索引問題

mysq order by 不走索引問題

問題描述

今天遇到一個問題,在一個報表匯出的功能中,需要匯出使用者的某些記錄的所有資料,有些使用者有多達10萬的記錄,匯出過程非常慢,需要10多秒。經過排查,發現是查詢資料庫的時候的問題,查詢資料居然用了7秒左右。起初看到sql沒發現什麼問,sql寫得中規中矩,只查詢需要的列,使用索引,遵循索引規則等等,但是它就是要那麼長時間。

問題分析

表面上看不出問題,那隻能用explain大法來分析分析了

原sql(這裡隱去關鍵資訊)

select drawno,col from `tb_loxxx` where drawno >'15010101' order by drawno  desc;

expalin結果
圖1
從extra裡出現了Using filesort,說明這裡是沒有走索引的,而且type為ALL,說明進行了一次全表掃描。而該表確實對drawno欄位建立了索引,那麼是什麼原因導致這裡出現Using filesort呢?在繼續分析前先來了解下Using filesort。如果對mysql稍有了解的話,就會知道Using filesort代表著mysql進行了排序操作。下面是官方的描述

Using filesort:
MySQL must do an extra pass to find out how to retrieve the rows in sorted order. The sort is done by going through all rows according to the join type and storing the sort key and pointer to the row for all rows that match the WHERE clause.
Mysql需要額外的一次傳遞,以找出如何按排序順序檢索行,通過根據聯接型別瀏覽所有行併為所有匹配where子句的行儲存排序關鍵字和行的指標來完成排序,然後關鍵字被排序,並按排序順序檢索行。

這句話直接翻譯過來有點難以理解,簡單說就是由於索引不滿足你的sql,mysql需要對資料行進行一次額外的排序操作,這個排序操作既費空間又費時間。當資料量較少的時候並不會對應用產生多大影響,但資料量一多,就會出現非常可怕的後果,輕則服務響應變慢,重則拖垮服務,甚至引發雪崩效應導致應用宕機。

再回來看看我的sql,查詢列和搜尋條件應該都沒有問題,那麼應該order by影響了。通過搜尋發現,order by 使用不當確實會導致索引失效。

解決方案

1.強制索引 FORCE INDEX(key)

force index 的作用是讓mysql強制使用某個索引,對應的有ignore index 強制忽略索引。除非非常明確sql目的和執行效率情況下,一般不推薦使用這2個操作:一是強制索引可能導致其他索引失效,二是強制索引不一定會提高sql效率,還會導致mysql優化器沒有作用,三是強制使用的索引如果被刪除了,會導致程式異常。
強制索引使用方式如下:

select drawno,col from `tb_loxxx` force index(tb_loxxx_01) where drawno >'15010101' order by drawno  desc;

再次進行expalin
圖2
可以看到使用了索引,type也變成了range。再次執行sql,發現sql的效率又回到正常水平了,僅用300多毫米就完成了這次查詢。

2.聯合索引

聯合索引就行將需要的列組成一個索引。這個需要根據具體sql分析。
針對我這個sql,是因為我的order by 和搜尋列不匹配,order by drawno,而搜尋列除了drawno,還有其他列,根據sql條件,我建立相應索引後,sql效率也迴歸到正常水平。

從效率上來說聯合索引和強制索引基本是一樣,從應用上來說聯合索引會好一些,但是如果sql複雜或者資料庫設計的混亂,可能造成一個表建立一堆索引的情況,索引太多對錶效能也有很多影響,最根本的解決方案還是簡化sql,去掉不必要的查詢等等。具體使用哪種方式,就看大家自己需要了。

參考

sql優化建議
單列索引和聯合索引
order by原理及filesort優化