mysql慢查詢排查處理
一、mysql優化的目的
事務阻塞,慢查詢
二、mysql優化的方向
sql及索引優化。
資料庫表結構,根據資料設計查詢最優的表結構。
系統配置優化,對開啟檔案數和安全的限制。
硬體,選擇最適合資料庫的cpu,更快的IO,更大的記憶體,cpu不是越多越好, IO並不能減少鎖的機制,也就是不能減少阻塞,所以說硬體的優化成本越高,效果最差。
三、mysql慢查詢日誌的開啟
slow_query_log
show_query_log_file:慢查日誌儲存位置
set global slow_query_log_file="D:/Program Files/mysql-5.6.44-winx64/loglocalhost-slow.log";
log_queries_not_use_indexes:是否把沒有使用索引的查詢記錄在檔案中
long_query_time:超過多少秒的查詢記錄下來
#開啟慢查詢日誌記錄 mysql> set global slow_query_log=on; Query OK, 0 rows affected (0.00 sec) #查詢時間超過0.1秒的sql語句會被記錄 mysql> set global long_query_time=0.1; Query OK, 0 rows affected (0.03 sec) #記錄慢查詢日誌的檔案地址 mysql> set global slow_query_log_file="/var/lib/mysql/localhost-slow.log"; Query OK, 0 rows affected (0.04 sec) #記錄沒有使用索引的查詢 mysql> set global log_queries_not_using_indexes=on; Query OK, 0 rows affected (0.00 sec) show variables like '%query%'; --命令檢視開啟狀態
show variables like 'slow_query_log'; --慢查詢是否開啟 show variables like 'long_query_time'; --慢查詢的閾值 show variables like 'slow_query_log_file'; --慢查日誌儲存位置 show variables like 'log_queries_not_using_indexes';
show variables 1ike 'max%'; -- max_connections最大連線數配置
/etc/my.cnf配置
# 在配置檔案的[mysqld]下面加入以下幾行
#開啟慢查詢日誌記錄
slow_query_log=1
#查詢時間超過1秒的sql語句會被記錄
long_query_time=0.9
#記錄沒有使用索引的查詢
log_queries_not_using_indexes=0
#記錄慢查詢日誌的檔案地址
slow-query-log-file=/data/slowQueryLog/slowQuery.log
四、explain命令檢查SQL
mysql> explain select * from staff;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | staff | ALL | NULL | NULL | NULL | NULL | 2 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set
先上一個官方文件表格的中文版:
Column | 含義 |
---|---|
id | 查詢序號 |
select_type | 查詢型別 |
table | 表名 |
partitions | 匹配的分割槽 |
type | join型別 |
prossible_keys | 可能會選擇的索引 |
key | 實際選擇的索引 |
key_len | 索引的長度 |
ref | 與索引作比較的列 |
rows | 要檢索的行數(估算值) |
filtered | 查詢條件過濾的行數的百分比 |
Extra | 額外資訊 |
這是explain結果的各個欄位,分別解釋下含義
1. id
SQL查詢中的序列號。
id列數字越大越先執行,如果說數字一樣大,那麼就從上往下依次執行。
2. select_type
查詢的型別,可以是下表的任何一種型別:
select_type | 型別說明 |
---|---|
SIMPLE | 簡單SELECT(不使用UNION或子查詢) |
PRIMARY | 最外層的SELECT |
UNION | UNION中第二個或之後的SELECT語句 |
DEPENDENT UNION | UNION中第二個或之後的SELECT語句取決於外面的查詢 |
UNION RESULT | UNION的結果 |
SUBQUERY | 子查詢中的第一個SELECT |
DEPENDENT SUBQUERY | 子查詢中的第一個SELECT, 取決於外面的查詢 |
DERIVED | 衍生表(FROM子句中的子查詢) |
MATERIALIZED | 物化子查詢 |
UNCACHEABLE SUBQUERY | 結果集無法快取的子查詢,必須重新評估外部查詢的每一行 |
UNCACHEABLE UNION | UNION中第二個或之後的SELECT,屬於無法快取的子查詢 |
DEPENDENT 意味著使用了關聯子查詢。
3. table
查詢的表名。不一定是實際存在的表名。
可以為如下的值:
- <unionM,N>: 引用id為M和N UNION後的結果。
- <derivedN>: 引用id為N的結果派生出的表。派生表可以是一個結果集,例如派生自FROM中子查詢的結果。
- <subqueryN>: 引用id為N的子查詢結果物化得到的表。即生成一個臨時表儲存子查詢的結果。
4. type(重要)
這是最重要的欄位之一,顯示查詢使用了何種型別。從最好到最差的連線型別依次為:
system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL
除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引。
-
1、system
表中只有一行資料或者是空表,這是const型別的一個特例。且只能用於myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index
-
2、const
最多隻有一行記錄匹配。當聯合主鍵或唯一索引的所有欄位跟常量值比較時,join型別為const。其他資料庫也叫做唯一索引掃描
-
3、eq_ref
多表join時,對於來自前面表的每一行,在當前表中只能找到一行。這可能是除了system和const之外最好的型別。當主鍵或唯一非NULL索引的所有欄位都被用作join聯接時會使用此型別。
eq_ref可用於使用'='操作符作比較的索引列。比較的值可以是常量,也可以是使用在此表之前讀取的表的列的表示式。
相對於下面的ref區別就是它使用的唯一索引,即主鍵或唯一索引,而ref使用的是非唯一索引或者普通索引。
eq_ref只能找到一行,而ref能找到多行。
-
4、ref
對於來自前面表的每一行,在此表的索引中可以匹配到多行。若聯接只用到索引的最左字首或索引不是主鍵或唯一索引時,使用ref型別(也就是說,此聯接能夠匹配多行記錄)。
ref可用於使用'='或'<=>'操作符作比較的索引列。
-
5、 fulltext
使用全文索引的時候是這個型別。要注意,全文索引的優先順序很高,若全文索引和普通索引同時存在時,mysql不管代價,優先選擇使用全文索引
-
6、ref_or_null
跟ref型別類似,只是增加了null值的比較。實際用的不多。
eg.
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;
-
7、index_merge
表示查詢使用了兩個以上的索引,最後取交集或者並集,常見and ,or的條件使用了不同的索引,官方排序這個在ref_or_null之後,但是實際上由於要讀取多個索引,效能可能大部分時間都不如range
-
8、unique_subquery
用於where中的in形式子查詢,子查詢返回不重複值唯一值,可以完全替換子查詢,效率更高。
該型別替換了下面形式的IN子查詢的ref:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
-
9、index_subquery
該聯接型別類似於unique_subquery。適用於非唯一索引,可以返回重複值。
-
10、range
索引範圍查詢,常見於使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等運算子的查詢中。
SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20;
SELECT * FROM tbl_name
WHERE key_column IN (10,20,30);
-
11、index
索引全表掃描,把索引從頭到尾掃一遍。這裡包含兩種情況:
一種是查詢使用了覆蓋索引,那麼它只需要掃描索引就可以獲得資料,這個效率要比全表掃描要快,因為索引通常比資料表小,而且還能避免二次查詢。在extra中顯示Using index,反之,如果在索引上進行全表掃描,沒有Using index的提示。
# 此表見有一個name列索引。
# 因為查詢的列name上建有索引,所以如果這樣type走的是index
mysql> explain select name from testa;
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | testa | index | NULL | idx_name | 33 | NULL | 2 | Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
1 row in set
# 因為查詢的列cusno沒有建索引,或者查詢的列包含沒有索引的列,這樣查詢就會走ALL掃描,如下:
mysql> explain select cusno from testa;
+----+-------------+-------+------+---------------