最近項目上遇到點問題,服務器出現連接超時。上次也是超時,問題定位到mongodb上,那次我修改好了,這次發現應該不是這個的問題了。
初步懷疑是mysql這邊出問題了,寫的sql沒經過壓力測試,導致用戶量多的時候,出現擁堵。
好,那就來看看mysql方便的慢查詢吧,來看看具體的哪些sql查詢慢,從這里開始來優化下。
一:開啟慢查詢
先來看看慢查詢日志設置的時間長度:
show VARIABLES LIKE 'long%'
返回,long_query_time 指定了慢查詢的閾值,即如果執行語句的時間超過該閾值則為慢查詢語句,默認值為10秒。這里設置的為1s

慢查詢日志開啟情況:
SHOW VARIABLES LIKE 'slow%'
返回:slow_query_log的值為ON為開啟慢查詢日志,OFF則為關閉慢查詢日志。
slow_query_log_file 的值是記錄的慢查詢日志到文件中(注意:默認名為主機名.log,慢查詢日志是否寫入指定文件中,需要指定慢查詢的輸出日志格式為文件,相關命令為:show variables like ‘%log_output%’;去查看輸出的格式)

通過以上命令,確定慢查詢已經打開了。然后去看慢查詢日志就行。
由於這里用的是阿里雲的數據庫,所以提供了后台可以很方便的查詢到日志和下載日志。

這里點擊下載即可將慢查詢的日志下載下來。
二:分析慢查詢日志
1. 截取一段慢查詢日志:
# Time: 180918 19:06:21 # User@Host: proxy[proxy] @ [192.168.0.16] Id: 6707197 # Query_time: 1.015429 Lock_time: 0.000116 Rows_sent: 1 Rows_examined: 44438 SET timestamp=1537268781; select id, user_id, device_uuid, bd_client_id, bd_user_id, bd_tag, nodisturb_mode, nodisturb_start_time, nodisturb_end_time, binding_time, device_os_type, app_type, state from app_mobile_device where user_id = '78436' and app_type = 'YGY' order by binding_time desc; # User@Host: proxy[proxy] @ [192.168.0.16] Id: 6707236 # Query_time: 1.021662 Lock_time: 0.000083 Rows_sent: 1 Rows_examined: 44438 SET timestamp=1537268781; select id, user_id, device_uuid, bd_client_id, bd_user_id, bd_tag, nodisturb_mode, nodisturb_start_time, nodisturb_end_time, binding_time, device_os_type, app_type, state from app_mobile_device where user_id = '14433' and app_type = 'YGY' order by binding_time desc;
這里可以看到:
Query_time (慢查詢語句的查詢時間) 都超過了設置的 1s,
Rows_sent (慢查詢返回記錄) 這里只返回了 1 條
Rows_examined (慢查詢掃描過的行數) 44438 -> 通過這里大概可以看出問題很大
2.現在將這個SQL語句放到數據庫去執行,並使用EXPLAIN分析 看下執行計划。
EXPLAIN select id, user_id, device_uuid, bd_client_id, bd_user_id, bd_tag, nodisturb_mode, nodisturb_start_time, nodisturb_end_time, binding_time, device_os_type, app_type, state from app_mobile_device where user_id = '78436' and app_type = 'YGY' order by binding_time desc;
查詢結果是:

解釋下參數:
| SELECT識別符。這是SELECT的查詢序列號 | |
| select_type | SELECT類型,可以為以下任何一種:
|
| table | 輸出的行所引用的表 |
| type | 聯接類型。下面給出各種聯接類型,按照從最佳類型到最壞類型進行排序:
|
| possible_keys | 指出MySQL能使用哪個索引在該表中找到行 |
| key | 顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。 |
| key_len | 顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。 |
| ref | 顯示使用哪個列或常數與key一起從表中選擇行。 |
| rows | 顯示MySQL認為它執行查詢時必須檢查的行數。多行之間的數據相乘可以估算要處理的行數。 |
| filtered | 顯示了通過條件過濾出的行數的百分比估計值。 |
| Extra | 該列包含MySQL解決查詢的詳細信息
|
這里可以發現:rows 為查詢的行數,查詢了4w多行,那慢是肯定的了。
因為這里是好幾個條件,並且沒有使用一個索引,那就只能給添加索引了,
這里給選擇添加普通多列索引,因為這個表在最開始設計出問題了,導致有重復的數據,不能設置唯一索引了。
ALTER TABLE app_mobile_device ADD INDEX user_app_type_only ( `user_id` ,`app_type` )
索引設置了,再看下剛的SQL的執行計划。

可以發現rows 的檢查行數,很明顯的下降了。
到此,慢查詢的使用和優化就基本完成了。
