一次mysql 優化 (Using temporary ; Using filesort)


遇到一個SQL執行很慢 SQL 如下:

SELECT 
	...
FROM 
	tableA 
WHERE time >= 1492044535 and time <= 1492046335 GROUP by time, sourceName, serverSite,clientSite;

SELECT 部分忽略沒寫,是因為通常SQL執行慢不會跟這部分有關系,至少我沒見過。

該語句非常簡單,但是執行太慢。所以我們看一下執行計划

執行計划有幾個字段我們比較關注:

type:range
possible_keys:time
key:time
extra:using index condition; using temporary; using filesort

type 代表連接類型。range是索引范圍掃描的時候顯示的類型。
possible_keys 和 keys 是可用的索引以及實際的索引
extra 比較關鍵,我們詳細看一下這里的信息:

filesort

是說在排序的時候,沒辦法使用索引。比如我們這里用的索引是time,但group by 是 time, sourceName, serverSite,clientSite。Mysql有一點很重要是會默認按照group by排序。

group by time, sourceName, serverSite, clientSite 

order by time, sourceName, serverSite, clientSite

開銷其實區別不大。所以這里排序不但要按照time 還要按照其它幾列

解決辦法

加order by null 這樣在group by的時候默認不排序,可以去掉filesort。 但實際測試發現還是慢,所以file sort不是性能關鍵。

using tempoaray

這里是說在mysql執行過程中產生了臨時表。這個操作比較耗時間。mysql的文檔列出了幾種會產生臨時表的語法,但和我們這里的情況都不相符合。倒是mariadb的文檔,雖然不是很詳細,但說明了我們的語句確實可能用到臨時表

A temporary table is created to hold the result. This typically happens if you are using GROUP BY, DISTINCT or ORDER BY.

仔細分析一下也有道理,用索引查到數據后,你需要對這些數據分組。這個過程肯定是在一個數據集上操作的,那么這個數據集應該就是臨時表了。不想要這個數據集的辦法就是取消這個分組操作。我們只需要create一個聯合索引

time,sourceName,serverSite,clientSite

這樣一個索引可以通過time過濾,天然按照分組的順序排序,就不用臨時表了。

同時可以在執行語句中加個force index強制執行這個索引。
這樣就沒有using temporary這個操作了


免責聲明!

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



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