常見SQL優化手段
慢SQL優化手段總結
- MySQL支援配置指定記錄慢查的資訊。
SHOW VARIABLES LIKE 'slow%’可以去顯示DB當前慢查的配置。
slow_launch_time表示建立執行緒花費超過這個閥值,slow_launch_threads計數增加。
slow_query_log是顯示慢查日誌是否開啟。
slow_query_log_file:日誌儲存路徑。
Long_query_time:SQL執行達到多少秒就記錄日誌。
SHOW VARIABLES LIKE ‘long%’
客戶端可以set開啟滿查詢也可以,但是重啟和修改配置檔案就失效了。
My.cnf:
slow_query_log=ON
slow_query_log_file=/var/lib/mysql/localhost-centos-slow.log
long_query_time=3
重啟MySQL就能在指定日誌看到超過3秒的慢SQL記錄。
- EXPLAIN命令
加在SELECT 語句前面,能看到執行計劃。
-
Id:
JOIN和子查詢(老版本貌似不支援)代表執行順序,id越大越先執行。
-
select_type:
Simple: 不使用表連線 union union後的查詢 Subquery 子查詢 Derived 派生表
-
Type
代表查詢資料的方式,按照查詢效能從差到好的排序 all 全表掃描,效能很差,一般可以加索引 Index 索引全掃描,遍歷索引查詢匹配的行 Range 索引範圍掃描,< > between等操作 Ref 使用一索引的字首掃描,返回單行 eq_ref 使用唯一索引掃描 Const/system 單表最多匹配一個,pk或則uk查詢 Null MySQL不用訪問表,直接返回結果
-
possible_keys
查詢可能使用的索引
-
Key:
實際使用的索引
-
key_len:
使用索引欄位的長度
-
Rows:
掃描數量
-
Extra:
額外的執行資訊
-
Using index :
直接訪問索引能夠取到資料,高效能表現
-
Using where :
直接主鍵索引過濾資料,必帶where,用不上索引 …
- 一些SQL語句優化
-
COUNT語句
COUNT()與COUNT(某個欄位)的區別是COUNT(某個欄位)統計欄位非NULL的行數。
COUNT(1)與COUNT()都是統計primary Key,效率一樣,如果沒有PK,全表掃描.
如果COUNT(column) ,其中column為索引,COUNT(column)和COUNT(1)一樣快,否則COUNT(column)走全表掃描。 -
ORDER BY 語句
有序索引extra 顯示Using Index的話,MySQL有序返回,效率非常高。
返回資料排序,Using file sort,使用排序演算法在sort_buffer_size系統變數設定的記憶體排序區中進行排序,記憶體裝不下在磁碟,然後合併結果。file sort優化,減少額外排序,建立合適索引,select * 改成指定的欄位,減少排序區的使用。 -
GROUP BY語句
GROUP BY預設加了ORDER BY ,不用再加ORDER BY
GROUP BY如果不關係排序,可以 ORDER BY NULL 禁止排序降低排序消耗。 -
LIMIT 語句
指定的範圍小可以先拿出key值再去查全部欄位, 避免查太多資料。
SELECT * FROM basic_warehouse bw INNER JOIN (SELECT id FROM basic_warehouse LIMIT 10,20) t ON t.id= bw.id
或則標記分頁開始位置:
SELECT * FROM basic_warehouse WHERE id > 100 LIMIT 10 -
子查詢
一般來說JOIN 比子查詢效率高 -
執行索引優先順序
指定走索引 SELECT * FROM basic_warehouse USE INDEX(name) 走索引複雜的IO的成本太高可能直接走全表掃描
評估後可以強制走索引SELECT * FROM basic_warehouse FORECE INDEX(name)
如果IO效率太低,可以讓MySQL忽略一個索引,SELECT * FROM basic_warehouse IGNORE INDEX(name) -
避免全表掃描
使用NULL值判斷會放棄索引走全表:WHERE name IS NULL。如果是char,建欄位就固定,是不是null都會佔100字元。varcher null不佔空間
設定預設值=0比欄位 IS NULL搜尋好。
使用!= 或則<>會導致掃描全表
Where a = 1 OR b = 2,不是兩個欄位都有索引的情況下,掃全表. 可以使用SELECT * FROM table WHERE a = 1 UNION ALL SELECT * FROM table WHERE b = 2
IN 和 NOT IN 都會掃全表, 很多時候可以用exits代替。
LIKE 模糊查詢全表掃描
WHERE 中有表示式操作會全表掃描。例如WHERE a - 1 = 10,改成 a= 11
WHERE 有函式表示式會掃描全表