記錄一次MySQL SQL語句優化

今天有一個客戶說,他拉取流水記錄總是超時。

我打開數據庫一看,流水記錄表有900萬數據。爲了方便描述問題,我們假設這張表的名字叫 t_flow。

其實拉取記錄的語句很簡單。

SELECT * FROM `t_flow` WHERE `time` > timestamp AND `userid`=my_userid OR `uuid`=my_userid ORDER BY `time` DESC LIMIT 0,10;

在900萬條數據的情況下,執行這條語句花了7秒多。這張表的各個列的索引都已建立

我一眼看到了`userid`=my_userid OR `uuid`=my_userid這個地方。 這是項目裏面爲了方便,同事設計的,不管my_userid是UUID還是真的userid都可以用同一個函數。好在我們的userid是6位,而uuid是10多位。所以我做了一個優化。 先判斷my_userid是uuid還是userid,這樣少了一個OR。 時間縮短到了5秒多。

僞代碼如下

if(my_userid.length == 6){
    SELECT * FROM `t_flow` WHERE `time` > timestamp AND `userid`=my_userid ORDER BY `time` DESC LIMIT 0,10;
}
else{
    SELECT * FROM `t_flow` WHERE `time` > timestamp AND `uuid`=my_userid ORDER BY `time` DESC LIMIT 0,10;
}

但是5秒多也不行啊。才這麼點數據。於是我去掉了LIMIT,發現,去掉LIMIT後,執行就只需要2秒多了。

百思不得其解。我於在網上搜索了許久的關於SQL語句中添加了LIMIT反而更慢的問題,仍未找到答案。

由於有900多萬條,而我用的是SELECT *,我懷疑是這裏有問題,導致WHERE語句在查找的時候,消耗了太多內存。

於是我做了一個新版本。

SELECT * FROM `t_flow` WHERE `uuid` IN( SELECT `uuid` FROM `t_flow` WHERE `time` > timestamp AND `userid`=my_userid OR `uuid`=my_userid) ORDER BY `time` DESC LIMIT 0,10;

先查找出uuid,再直接獲取uuid的內容。這樣有一個好處就是,在進行 time > timestamp篩選的時候,只拿出了uuid,減少了內存開銷。 

因爲我們的MYSQL服務器的內存有限,如果大量的內存開銷就會觸發內存頁面置換,從而導致花更多的時間。

最後本條語句執行只花了400ms,由於只是一個數據統計功能,所以免強算達標。

發佈了233 篇原創文章 · 獲贊 546 · 訪問量 119萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章