談談SQL慢查詢的解決思路

最近,在運維部及DBA同事的幫助和大家的共同努力下,對項目中的慢SQL進行了優化和修正,效果還是很明顯的,在此給大家點一個大大的贊。爲了讓我們在SQL的處理上更爲合理,形成可實踐、可借鑑、可參考優化的方案,我在這裏梳理一下慢SQL的解決思路,供大家參考。

慢SQL的系統表現

首先,我們如何判別系統中遇到了SQL慢查詢問題?個人認爲慢SQL有如下三個特徵:

1,數據庫CPU負載高。一般是查詢語句中有很多計算邏輯,導致數據庫cpu負載。

2,IO負載高導致服務器卡住。這個一般和全表查詢沒索引有關係。

3,查詢語句正常,索引正常但是還是慢。如果表面上索引正常,但是查詢慢,需要看看是否索引沒有生效。

開啓SQL慢查詢的日誌

如果你的系統出現了上述情況,並且你不是用的阿里雲的RDS這樣的產品,那麼下一步就需要打開Mysql的慢查詢日誌來進一步定位問題。MySQL 提供了慢查詢日誌,這個日誌會記錄所有執行時間超過 long_query_time(默認是10s)的 SQL 及相關的信息。

要開啓日誌,需要在 MySQL 的配置文件 my.cnf 的 [mysqld] 項下配置慢查詢日誌開啓,如下所示:

[mysqld]slow_query_log=1
slow_query_log_file=/var/log/mysql/log-slow-queries.log
long_query_time=2複製代碼

在實際項目中,由於生成的慢查詢的日誌可能會特別大,分析起來不是很

方便,所以Mysql官方也提供了 mysqldumpslow 這個工具,方便我們分析慢查詢日誌,感興趣的同學可以自行到Mysql官方進行查閱。

SQL調優

有些SQL雖然出現在慢查詢日誌中,但未必是其本身的性能問題,可能是因爲鎖等待,服務器壓力高等等。需要分析SQL語句真實的執行計劃,而不是看重新執行一遍SQL時,花費了多少時間,由自帶的慢查詢日誌或者開源的慢查詢系統定位到具體的出問題的SQL,然後使用Explain工具來逐步調優,瞭解 MySQL 在執行這條數據時的一些細節,比如是否進行了優化、是否使用了索引等等。基於 Explain 的返回結果我們就可以根據 MySQL 的執行細節進一步分析是否應該優化搜索、怎樣優化索引。

關於索引的創建及優化原則,個人特別推薦美團點評技術團隊的幾點總結,講得特別好,特地引用一下:

  1. 最左前綴匹配原則,非常重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整;

  2. =和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式;

  3. 儘量選擇區分度高的列作爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大我們掃描的記錄數越少,唯一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不同,這個值也很難確定,一般需要join的字段我們都要求是0.1以上,即平均1條掃描10條記錄;

  4. 索引列不能參與計算,保持列“乾淨”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,需要把所有元素都應用函數才能比較,顯然成本太大。所以語句應該寫成create_time = unix_timestamp(’2014-05-29’);

  5. 儘量的擴展索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可。

一點總結

基於本文的思路,關於SQL慢查詢的解決可以按照以下的步驟執行:

1. 打開慢日誌查詢,確定是否有SQL語句佔用了過多資源,如果是,在不改變業務原意的前提下,對insert、group by、order by、join等語句進行優化。

2. 考慮調整MySQL的系統參數: innodb_buffer_pool_sizeinnodb_log_file_sizetable_cache等。

3. 確定是否是因爲高併發引起行鎖的超時問題。

4. 如果數據量過大,需要考慮進一步的分庫分表。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章