Mysql 優化,慢查詢


最近項目上遇到點問題,服務器出現連接超時。上次也是超時,問題定位到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類型,可以為以下任何一種:

  • SIMPLE:簡單SELECT(不使用UNION或子查詢)
  • PRIMARY:最外面的SELECT
  • UNION:UNION中的第二個或后面的SELECT語句
  • DEPENDENT UNION:UNION中的第二個或后面的SELECT語句,取決於外面的查詢
  • UNION RESULT:UNION 的結果
  • SUBQUERY:子查詢中的第一個SELECT
  • DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決於外面的查詢
  • DERIVED:導出表的SELECT(FROM子句的子查詢)
table

輸出的行所引用的表

type

聯接類型。下面給出各種聯接類型,按照從最佳類型到最壞類型進行排序:

  • system:表僅有一行(=系統表)。這是const聯接類型的一個特例。
  • const:表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩余部分認為是常數。const表很快,因為它們只讀取一次!
  • eq_ref:對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。
  • ref:對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。
  • ref_or_null:該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。
  • index_merge:該聯接類型表示使用了索引合並優化方法。
  • unique_subquery:該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
  • index_subquery:該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
  • range:只檢索給定范圍的行,使用一個索引來選擇行。
  • index:該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
  • ALL:對於每個來自於先前的表的行組合,進行完整的表掃描。
possible_keys

指出MySQL能使用哪個索引在該表中找到行

key 顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
key_len 顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
ref 顯示使用哪個列或常數與key一起從表中選擇行。
rows 顯示MySQL認為它執行查詢時必須檢查的行數。多行之間的數據相乘可以估算要處理的行數。
filtered 顯示了通過條件過濾出的行數的百分比估計值。
Extra

該列包含MySQL解決查詢的詳細信息

  • Distinct:MySQL發現第1個匹配行后,停止為當前的行組合搜索更多的行。
  • Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標准的行后,不再為前面的的行組合在該表內檢查更多的行。
  • range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
  • Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
  • Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
  • Using temporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
  • Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
  • Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合並索引掃描。
  • Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查 詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。

 這里可以發現:rows 為查詢的行數,查詢了4w多行,那慢是肯定的了。

因為這里是好幾個條件,並且沒有使用一個索引,那就只能給添加索引了,

這里給選擇添加普通多列索引,因為這個表在最開始設計出問題了,導致有重復的數據,不能設置唯一索引了。

ALTER  TABLE  app_mobile_device  ADD  INDEX user_app_type_only (  `user_id` ,`app_type` )

 索引設置了,再看下剛的SQL的執行計划。

可以發現rows 的檢查行數,很明顯的下降了。

到此,慢查詢的使用和優化就基本完成了。

 


免責聲明!

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



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