Mysql 優化,慢查詢

最近項目上遇到點問題,服務器出現鏈接超時。上次也是超時,問題定位到mongodb上,那次我修改好了,此次發現應該不是這個的問題了。java

初步懷疑是mysql這邊出問題了,寫的sql沒通過壓力測試,致使用戶量多的時候,出現擁堵。mysql

 

好,那就來看看mysql方便的慢查詢吧,來看看具體的哪些sql查詢慢,從這裏開始來優化下。sql

一:開啓慢查詢mongodb

先來看看慢查詢日誌設置的時間長度:數據庫

  show VARIABLES LIKE 'long%'

 返回,long_query_time 指定了慢查詢的閾值,即若是執行語句的時間超過該閾值則爲慢查詢語句,默認值爲10秒。這裏設置的爲1s服務器

慢查詢日誌開啓狀況:app

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 的檢查行數,很明顯的降低了。

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

相關文章
相關標籤/搜索