1. 程式人生 > 其它 >mysql慢查詢排查處理

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;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | testa | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set

# 包含有未見索引的列
mysql> explain select * from testa;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | testa | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set
  • 12、all

全表掃描,效能最差。

5. partitions

版本5.7以前,該項是explain partitions顯示的選項,5.7以後成為了預設選項。該列顯示的為分割槽表命中的分割槽情況。非分割槽表該欄位為空(null)。

6. possible_keys

查詢可能使用到的索引都會在這裡列出來

7. key

查詢真正使用到的索引。
select_type為index_merge時,這裡可能出現兩個以上的索引,其他的select_type這裡只會出現一個。

8. key_len

查詢用到的索引長度(位元組數)。
如果是單列索引,那就整個索引長度算進去,如果是多列索引,那麼查詢不一定都能使用到所有的列,用多少算多少。留意下這個列的值,算一下你的多列索引總長度就知道有沒有使用到所有的列了。

key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。

9. ref

如果是使用的常數等值查詢,這裡會顯示const,如果是連線查詢,被驅動表的執行計劃這裡會顯示驅動表的關聯欄位,如果是條件使用了表示式或者函式,或者條件列發生了內部隱式轉換,這裡可能顯示為func

10. rows(重要)

rows 也是一個重要的欄位。 這是mysql估算的需要掃描的行數(不是精確值)。
這個值非常直觀顯示 SQL 的效率好壞, 原則上 rows 越少越好.

11. filtered

這個欄位表示儲存引擎返回的資料在server層過濾後,剩下多少滿足查詢的記錄數量的比例,注意是百分比,不是具體記錄數。這個欄位不重要

12. extra(重要)

EXplain 中的很多額外的資訊會在 Extra 欄位顯示, 常見的有以下幾種內容:

  • distinct:在select部分使用了distinc關鍵字
  • Using filesort:當 Extra 中有 Using filesort 時, 表示 MySQL 需額外的排序操作, 不能通過索引順序達到排序效果. 一般有 Using filesort, 都建議優化去掉, 因為這樣的查詢 CPU 資源消耗大.
# 例如下面的例子:

mysql> EXPLAIN SELECT * FROM order_info ORDER BY product_name \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: order_info
   partitions: NULL
         type: index
possible_keys: NULL
          key: user_product_detail_index
      key_len: 253
          ref: NULL
         rows: 9
     filtered: 100.00
        Extra: Using index; Using filesort
1 row in set, 1 warning (0.00 sec)
我們的索引是

KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`)
但是上面的查詢中根據 product_name 來排序, 因此不能使用索引進行優化, 進而會產生 Using filesort.
如果我們將排序依據改為 ORDER BY user_id, product_name, 那麼就不會出現 Using filesort 了. 例如:

mysql> EXPLAIN SELECT * FROM order_info ORDER BY user_id, product_name \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: order_info
   partitions: NULL
         type: index
possible_keys: NULL
          key: user_product_detail_index
      key_len: 253
          ref: NULL
         rows: 9
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)
  • Using index
    "覆蓋索引掃描", 表示查詢在索引樹中就可查詢所需資料, 不用掃描表資料檔案, 往往說明效能不錯

  • Using temporary
    查詢有使用臨時表, 一般出現於排序, 分組和多表 join 的情況, 查詢效率不高, 建議優化.

除此之外還有其他值,這裡就不一一一列舉了。



作者:Katou_Megumi
連結:https://www.jianshu.com/p/8fab76bbf448
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。