當前位置:
首頁 > 最新 > MySQL性能優化之SQL語句優化

MySQL性能優化之SQL語句優化

前言

這個話題其實難度蠻大的,因為不但需要理解一些Mysql的專業知識,同時還需要長時間的觀察統計,以及大量的使用經驗

之前在某項目中,服務端發生過兩起關於Mysql的頻繁大量拋錯的事件,一個是拋出Mysql異常" too many connections", 另一個是拋出Mysql異常 " open too many files",這促使我開始重視起Mysql的性能優化。


優化目標

IO永遠是資料庫最容易瓶頸的地方,這是由資料庫的職責所決定的,大部分資料庫操作中超過90%的時間都是 IO 操作所佔用的,減少 IO 次數是 SQL 優化中需要第一優先考慮,當然,也是收效最明顯的優化手段。


除了 IO 瓶頸之外,SQL優化中需要考慮的就是 CPU 運算量的優化了。order by, group by,distinct … 都是消耗 CPU 的大戶(這些操作基本上都是 CPU 處理內存中的數據比較運算)。當我們的 IO 優化做到一定階段之後,降低 CPU 計算也就成為了我們 SQL 優化的重要目標

優化方向

2.資料庫表結構的優化

3.系統配置的優化

4.硬體的優化


SQL語句及索引的優化

(1)使用mysql慢查詢日誌監控有效率問題的SQL語句

檢查滿查詢日誌是否開啟

mysql> show variables like "%slow%";

(2)開啟慢查詢日誌

開啟

mysql> set global slow_query_log="ON";

設置記錄慢查詢的時間閥值

mysql> set global long_query_time=0.1;

即超過100ms的查詢就認為是慢查詢

(註:slow_launch_time 表示如果建立線程花費了比這個值更長的時間,slow_launch_threads 計數器將增加)

記錄沒有使用索引的查詢

mysql> set global log_queries_not_using_indexes=on;

開啟慢查詢日誌的操作也可以在MySQL的配置文件my.cnf中添加以下兩行:

log-slow-queries=/var/run/mysqld/mysqld-slow.log

long_query_time=0.1

(3)使用慢查詢日誌分析工具:mysqldumpslow或mysqlsla

mysqldumpslow是官方提供的,在安裝Mysql時就已經自帶了,使用方法請自行輸入命令 mysqldumpslow --help查看。

mysqlsal是hackmysql.com推出的,功能非常強大,請自行google其安裝步驟和使用方法。


例如:mysql> explain select * from file;

mysql> explain select * from file where fid > 0;

比較以上兩條語句的執行結果。

EXPLAIN語句返回結果中列的解釋:

table:這行數據的所屬表的表名字

type顯示連接使用了何種類型。從最好到最差的連接類型為const、eq_reg、ref、range、index和ALL

const:表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因為只有一行,這個值實際就是常數,因為MYSQL先讀這個值然後把它當做常數來對待

eq_ref:MYSQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用

ref:只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好

range:使用索引返回一個範圍中的行,比如使用>或

index:對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因為索引一般小於表數據)

ALL:對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該盡量避免

possible_keys:顯示可能應用在這張表中的索引。如果為空,沒有可能的索引。可以為相關的域從WHERE語句中選擇一個合適的語句

key: 實際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引

key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好

ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數

rows:MYSQL認為必須檢查的用來返回請求數據的行數

Extra:關於MYSQL如何解析查詢的額外信息。Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢,會創建臨時表或文件來存儲結果,造成大量的IO操作,影響效率


(1)max()優化

max(A) 給max函數里的欄位A添加索引

mysql> create index idx_A on table B(A)

此時若用 EXPLAIN語句再次分析,會在Extra列中看到如下返回:

表示不需要查詢,只需要通過索引就可以找出查詢結果,這條索引叫覆蓋索引,就是select的數據列只用從索引中就能夠取得,不必讀取數據行,換句話說查詢列要被所建的索引覆蓋。

(2)count()優化

在不加where限制條件的情況下, count(*)與 count(COL)基本可以認為是等價的;

但是在有where限制條件的情況下, count(*)會比 count(COL)快非常多;

count(*)通常是對主鍵進行索引掃描,而 count(COL)就不一定了,另外前者是統計表中的所有符合的紀錄總數,而後者是計算表中所有符合的列的紀錄數。另外,count(*)會包含NULL值


通常情況下需要把子查詢優化為join查詢,但在優化時要注意關聯鍵是否有一對多的關係,注意重複數據:

select tid from t1 where tid in (select id from t);

改成

selectdistinctt1.tid from t1 join t2 on t1.tid = t.id;


limit常用於分頁處理,會伴隨order by 語句,因為會使用FileSorts 這樣會造成大量的IO問題

優化1:使用有索引的列或主鍵進行order by操作

不使用索引列的語句:

使用索引列後的語句:

對比以上兩條語句可以看到type從ALL變成了index。

但隨著翻頁越來越往後,掃描的行數會越來越多, 實際上響應速度會越來越慢

查詢第一頁:

查詢第N頁

對比以上兩條,可以看到掃描的行數明顯增加了。因此需要進一步優化。

優化步驟2:

記錄上次返回的主鍵,在下次查詢的時候使用主鍵過濾 (避免數據量大時掃描過多的記錄)

可以看到掃描行數明顯減少。


(1)在where從句,group by從句, order by從句, on從句中出現的列

(2)索引欄位越小越好(資料庫存儲是以頁為單位的,一頁里能存越多數據,一次IO操作獲取的數據量越大,效率更高)

(3)離散度大的列放到聯合索引前面

如何判斷哪個列離散度高?

select count(A), count(B) from X;

如果count(A)的值大於count(B)的值,那麼說明A欄位的離散度大,選擇範圍會更大,需要以A為主要排序欄位,索引應該為index(A,B) 而不是inde(B,A)


建立索引會有利於查詢但是會影響insert和update、delete等更新操作

並且過多的索引也會影響查詢,不利於資料庫分析和選擇索引

重複索引:設為主鍵的欄位不需要再加索引了

冗餘索引:在聯合索引中包含了主鍵的索引,對於innodb來說,每一個索引後面都會附加主鍵信息,這個時候就是冗餘的。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 瘋狂牛人 的精彩文章:

TAG:瘋狂牛人 |