1. SQL性能下降原因
開始由于數據較少,SQL的執行效率不會有太大影響,但當業務數據增多時,SQL的性能會逐漸下降。SQL性能下降主要有以下4種原因
- SQL語言寫的差【引起全表搜索,創建臨時表等】導致SQL性能下降
- 索引失效
- 查詢語句關聯了太多JOIN
- 服務器參數設置存在問題【緩沖區等】
2. SQL調優
SQL調優主要分為4個步驟:
- 慢查詢語句的捕獲
- 使用explain分析低效語句
- show profile分析低效語句
- SQL數據庫服務器的調優
2.1 慢查詢的開啟和捕獲
2.1.1 查看日志開啟情況
進入mysql后,可以使用show variables like '%low_query_log%'來查看慢查詢日志開啟情況,結果會返回slow_query_log的開啟情況,一般是off,還有slow_query_log所在的位置
mysql -u root -p # 今天mysql
# Enter password
show variables like '%slow_query_log%';
2.1.2 開啟日志
輸入set global slow_query_log = 1;開啟慢查詢日志
注意在調式時才打開慢查詢日志,平時不需要打開
set global slow_query_log = 1; # 開啟慢查詢日志
set global slow_query_log = 0; # 關閉慢查詢日志
2.1.3 查看和設置閾值
多慢的sql語句才會被記錄在慢查詢日志中呢?這時候就需要調整閾值,使用show variables like '%long_query_time%';可以查看當前的閾值,一般默認是10s
如果需要更小或者更大的閾值,可以使用set global long_query_time = ;來設定理想的閾值,根據實際情況設定對應閾值
show variables like '%long_query_time%';
set global long_query_time = 3; # 設定閾值為3秒
2.1.4 查看低效SQL
在mysql中輸入 show global status like'%slow_queries%'來查看低于閾值的sql語句條數,然后根據查詢慢日志是否開啟返回的結果slow_query_log可以查看慢查詢日志文件所在位置,打開慢查詢日志查看慢于閾值的低效SQL語句
show global status like'%slow_queries%'
慢查詢日志主要是用于低效SQL語句的捕獲,捕獲了對應的低效SQL語句后,就可以對其進行分析
2.2 使用explain分析
對于慢查詢日志捕獲的低效SQL語句,可以使用explain進行分析,分析其低效的原因
explain + SQL語句 可以查看單個SQL語句的執行計劃,模擬優化器執行SQL語句,從而知道MYSQL是如何處理MYSQL語句的,進而分析查詢語句或表結構的性能瓶頸
使用explian + SQL語句后會出現如圖所示表格,各參數意義如下:
-
id:一組數字,表示查詢中執行select子句或操作表的順序
- d相同時,執行順序由上至下
- d不同,id值越高,越先執行 -
select_type:查詢類型
- SIMPLE:代表類型是簡單查詢
- PRIMARYKEY:代表主查詢
- UNION:UNION查詢
- UNION:UNION返回的結果
- SUBQUERY:子查詢 -
type:訪問類型
- ALL:全表掃描
-** const**:代表常量
- eq_ref:唯一性索引掃描,只記錄一條記錄與之匹配
- ref:代表非唯一性索引掃描,返回匹配某個單獨值得所有行
- range:只檢索給定范圍得行,使用一個索引來選擇行
- system:表中僅有一行
type類型從優到差的順序為system > const > eq_ref > ref > range > index > ALL
要盡量避免出現ALL,因為全表掃描嚴重影響SQL性能
possible_key:顯示可能應用在表中的索引,一個或多個【但不一定被查詢使用】
key:實際使用的索引【如果為NULL,要么沒有建立,要么索引失效】
key_len:表示索引中使用的字節數【同樣查詢結果得情況下,key_len越小越好】
ref:顯示索引的哪一列被實際使用了
row:根據表統計信息及索引選用情況,大致估算出找到所需得記錄所需讀取的行數【越少越好】
Extra:包含不適合在其他列中顯示但十分重要得額外信息
- using filesort:文件內排序【盡量不要有using filesort】
- using temporary:新建內部得臨時表【盡量不要生成臨時表常見于order by 和 group by】
- using index:表明相應得select操作中使用了覆蓋索引,避免訪問了表得數據行【盡量有using index】
- using join buffer :使用了連接緩存
- impossible where:where子句得值總是False,不能用來獲取任何元組
- distinct
實際使用時,主要考察,id;type;key;row;Extra。考察type中是否有ALL;key是否存在索引失效;extra是否存在using filesort和using temporary這些嚴重影響性能的情況
2.3 使用show profile分析
對比explain,使用show profile可以更進一步分析低效的SQL 語句
show profile 提供可以用來分析當前會話中語句執行的資源消耗情況,用于SQL的調優測量,默認情況下,參數處于關閉狀態
2.3.1 開啟profile
使用SHOW VARIABLES LIKE 'profiling';查看profiling開啟狀態,默認關閉,保存15條運行結果
使用SET PROFILING=on; 開啟profiling
SHOW VARIABLES LIKE 'profiling'; # 查看profiling開啟狀態
SET PROFILING=on; # 開啟profiling
2.3.2 分析prifile
開啟profile后,SQL語句會被記錄在profiles中,使用show profiles; 可以查看語句對應的id和運行時間
一般查看cpu占用和io情況,可以使用show profile cpu ,block io for query <id>;來查看對應id語句的cpu和io情況,也可以改為ALL查看全部信息
show profiles # 查看profiles
show profile cpu ,block io for query 3; # 3可以改為其他id值
2.3.3. 相關結果說明
converting HEAP to MYISAM #查詢結果太大,內存不夠用了往磁盤上搬了
Creating tmp table #創建臨時表
Copying to tmp table on disk ; #把內存中臨時表復制到硬盤
2.4 SQL數據庫服務器的調優
增大buffer緩沖區等方法進行數據庫服務器調優
2.5 索引分析
2.5.1 索引基本概念
索引的概念:索引是幫助MYSQL高效獲取數據得數據結構,可以簡單理解為排好序得,幫助快速查找得數據結構
-
索引優勢
- 提高數據檢索效率,降低io成本
- 降低數據排序的成本,降低cpu的損耗
-
索引劣勢
- 索引實際上是一張表,也是要占用空間
- 會降低表的更新速度【因為要同時更新索引】
MYSQL索引基本語法
CREATE INDEX [indexName] ON 表明(列名) # 創建索引
DROP INDEX [indexName] ON mytable; # 刪除索引
SHOW INDEX FROM table_name # 查看索引
SELECT * FROM TABLE1 FORCE INDEX (FIELD1) … # 強制索引
SELECT * FROM TABLE1 IGNORE INDEX (idx_)… # 忽略索引
2.5.2 索引失效
在索引上執行操作時【計算、函數、類型轉換等】會導致索引失效
使用不等于(!=或 <>)時無法使用索引會導致全表掃描
is null 和 is not null無法使用索引
like以通配符開頭('%abc'或‘%abc%’)會導致索引失效,導致全表掃描
字符串varchar不加單引號會導致索引失效
用or連接會導致索引失效
使用復合索引索引了多列,沒有從最左列索引開始使用,或者跳過了索引中的前面的索引列而使用了后面的索引列【沒有使用全部索引】
如果使用了所有索引【沒有缺失】那么sql會自動優化索引順序,即查詢的索引順序不需要和索引建立的順序一致,也不存在范圍條件右邊索引列失效的問題-
范圍條件右邊的索引列會失效
- 例如:where age > 25 and pos='manager';,則pos上的索引會失效
2.5.3 索引優化
SQL索引失效主要是由于上述8種情況,除了注意避免以上情況導致的索引失效外,還要注意在建立索引上的優化
在建立索引時,要注意以下幾種問題:
- 索引最好設置在經常查詢的字段中
- 使用LEFT JOIN 和RIGHT JOIN 時方向要和索引相反
- LEFT JOIN主要受右表得影響,因此使用時,index要在右表
- RIGHT JOIN 主要受左表得影響,因此使用時,index要在左表