1. 如何獲取性能有問題的SQL
通過用戶反饋獲取存在性能問題的SQL
通過慢查日誌獲取存在性能問題的SQL
實時獲取存在性能問題的SQL
2. 使用慢查詢日誌獲取有性能問題的SQL
slow_query_log 啓動停止記錄慢查日誌,set global slow_query_log=on
slow_query_log_file 指定慢查日誌的存儲路徑及文件,默認情況下保存在Mysql的數據目錄中,建議分別存儲在不同目錄中
long_query_time 指定記錄慢查日誌SQL執行時間的伐值,單位:s,默認爲10s,通常改爲0.001秒(1毫秒)比較合適
log_query_not_using_indexes 是否記錄未使用索引的SQL
常用的慢查詢分析工具(mysqldumpslow)
彙總除查詢條件外其他完全相同的sql,並將分析結果按照參數中所指定的順序輸出。
mysqldumpslow -s r -t 10 slow-mysql.log
其中,
-s order(c,t,l,r,at,al,ar)指定按照那種順序輸出結果,c:總次數,t:總時間,l:鎖的時間,r:總數據行,at,ar,al:平均總次數,平均總行數,平均鎖的時間
-t top 指定取前幾條作爲輸出結果
常用的慢查詢分析工具(pt-query-digest)
3.如何實時獲取有性能問題的SQL
SELECT id,user
,host
,DB,command,time
,state,info FROM information_schema.PROCESSLIST WHERE TIME>60,此SQL用於查詢當前服務器中查詢時間超過60s的SQL,TIME值可根據實際情況修改
4.查詢速度爲什麼會慢
客戶端發送SQL請求給服務器
服務器查詢是否可以在查詢緩存中命中該SQL,命中則直接返回結果,未命中則進入下一階段
服務器進行SQL解析,預處理,再由優化器生成對應的執行計劃
根據執行計劃,調用存儲引擎API來查詢數據
將結果返回給客戶端
優先檢查這個查詢是否命中查詢緩存中的數據
查詢緩存是通過一個對大小寫敏感的哈希實現的,Hash查找只能進行全值匹配,只有當前查詢玩完全匹配緩存中的查詢時,才能命中緩存,若查詢命中,則校驗用戶權限,權限通過後直接返回結果,否則進入下一個階段。
query_cache_type 設置查詢緩存是否可用
- ON:開啓查詢緩存
- OFF:關閉查詢緩存
- DEMAND:表示只有在查詢語句中使用SQL_CACHE和SQL_NO_CACHE來控制是否需要緩存
query_cache_size 設置查詢緩存的內存大小,必須是1024整倍數
query_cache_limit 設置查詢緩存可用存儲的最大值,超過這個值則不會被緩存
query_cache_wlock_invalidate 設置數據表被鎖後是否返回緩存中的數據,默認關閉
query_cache_min_res_unit 設置查詢緩存分配的內存塊最小單位
如果數據庫有較頻繁的讀寫操作,建議將查詢緩存關閉,將query_cache_type設置爲OFF,將query_cache_size設置爲0
當查詢緩存未啓用或者查詢未命中緩存,則進入下一個階段,將SQL轉換成執行計劃
MYSQL按照執行計劃和存儲引擎進行交互,包括多個子階段
- 解析SQL,預處理,優化SQL執行計劃。
- 語法解析是通過關鍵字對MYSQL語句進行解析,並生成一顆對應的“解析樹”,MYSQL解析器將使用MYSQL語法規則驗證和解析查詢,包括語法是否使用了正確的關鍵字,關鍵字的順序是否正確等;
- 預處理階段則進一步檢查解析數是否合法,檢查查詢中所涉及的表和數據列存在,及名字和別名是否存在歧義等;
- 語法檢查通過了,查詢優化器就可以生成查詢計劃了
會造成MYSQL生成錯誤的執行計劃的原因
- 統計信息不準
- 執行計劃中的成本估算不等同於實際的執行計劃的成本,因爲MYSQL服務器層並不知道哪些頁面在內存中,哪些頁面在磁盤上,哪些頁面需要順序讀取,哪些頁面需要隨機讀取
- MYSQL優化器所認爲的最優可能與你所認爲的最優不一樣,MYSQL基於其成本模型選擇最優的執行計劃,有時候這並不是最快的執行計劃
- MYSQL不會考慮其他併發的查詢,這可能會影響當前查詢的速度
- MYSQL有時會基於一些固定的規則來生成執行計劃
- MYSQL不會考慮不受其控制的成本,比如執行存儲過程、用戶自定義的函數
重新定義表的關聯順序,優化器會根據表的信息決定表的關聯順序
將外連接轉換爲內連接
使用等價變化規則,例如(5 = 5 and a>5)將被改寫爲a>5
優化count(),min(),max()
將一個表達式轉化爲常數表達式
子查詢優化
提前終止查詢
對in()條件進行優化
5. 如何確定查詢處理各個階段所消耗的時間
set profiling = 1,啓動profile,這是一個session級的配置
執行查詢
show profiles;查看每一個查詢所消耗的總時間的信息
show profile for query N;N爲上一條命令顯示的QUERY_ID值,查詢每個階段所消耗的時間
6. 特定SQL的優化查詢
如何優化not in 或 <> 查詢
例如:
SELECT customer_id,first_name,lst_name,email
FROM customer
WHERE customer_id
NOT IN (SELECT customer_id FROM payment)
優化後:
SELECT customer_id,first_name,lst_name,email
FROM customer a
LEFT JOIN payment b ON a.customer_id = b.customer_id
WHERE b.customer_id IS NULL
使用匯總表優化查詢
SELECT COUNT(*) FROM product_comment WHERE product_id = 999,如果表中有上億條記錄,統計就會很慢
彙總表就是提前以要統計的數據進行彙總並記錄到表中以備後續的查詢使用
7. 相關文章
如何正確高效使用mysql的索引–索引優化策略
如何正確高效使用mysql的索引——Btree索引和Hash索引