本文轉載自: https://www.93bok.com
訪問網頁504 Gateway Time-out,登陸服務器查看,內存正常,CPU使用率達到了400%,因為是4核,所以到了400%,幾乎全部滿負載在跑了,又在下圖中發現,單單一個mysqld的進程,就占了390%,毫無疑問,數據庫的問題導致了網頁504。
1、使用top看到的情況如下
2、登陸數據庫,輸入show full processlist;可以看到正在執行的語句
可以看到是下面的SQL語句執行耗費了較長時間:
SELECT id,title,most_top,view_count,posttime FROM article where status=3 AND catalog_id in (select catalog_id from catalog where catalog_id=17 or parent_id=17) order by most_top desc,posttime desc limit 0,8
還可以從show full processlist命令中得出下圖中的端口號,我們也可以使用netstat -anupt | grep 端口號查看一下是什么進程打開的這個MySQL連接,這里我就不演示了,你們可以自己嘗試排查一下問題。
3、但是從數據庫設計方面來說,該做的索引都已經做了,SQL語句似乎沒有優化的空間。
直接執行此條SQL,發現速度很慢,需要7-8秒的時間(跟mysql正在並發執行的查詢有關,如果沒有並發的,需要1秒多)。如果把排序依據改為一個,則查詢時間可以縮短至0.01秒(most_top)或者0.001秒(posttime)。
4、通過EXPLAIN分析這條SQL語句
EXPLAIN SELECT id,title,most_top,view_count,posttime FROM article where status=3 AND catalog_id in (select catalog_id from catalog where catalog_id=17 or parent_id=17) order by most_top desc,posttime desc limit 0,8
可以看到,select對45萬條記錄使用filesort進行排序,這是造成查詢速度慢的原因。
5、優化
首先是縮減查詢范圍
SELECT id,title,most_top,view_count,posttime FROM article where status=3 AND catalog_id in (select catalog_id from catalog where catalog_id=17 or parent_id=17) and DATEDIFF(NOW(),posttime)<=90 order by most_top desc,posttime desc limit 0,8
發現有一定效果,但效果不明顯,原因是每條記錄都要做一次DATEDIFF運算。后改為
SELECT id,title,most_top,view_count,posttime FROM article where status=3 AND catalog_id in (select catalog_id from catalog where catalog_id=17 or parent_id=17) and postime>='2017-09-05' order by most_top desc,posttime desc limit 0,8
查詢速度大幅提高。
6、效果
查詢時間大幅度縮減,CPU負載很輕,頁面恢復正常