MySQL 之 慢查詢優化及慢日誌管理

一、查詢優化神器 —— explain

​ 使用EXPLAIN關鍵字能夠模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理SQL語句的。分析查詢語句或是表結構的性能瓶頸。html

(1)、經過EXPLAIN,能夠分析出如下結果:

  • 表的讀取順序
  • 數據讀取操做的操做類型
  • 哪些索引可使用
  • 哪些索引被實際使用
  • 表之間的引用
  • 每張表有多少行被優化器查詢

(2)、使用方式:

EXPLAIN + SQL語句

(3)、執行計劃包含的信息

+----+-------------+-------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table       | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+------+-------+

(4)、執行計劃各字段的含義

<1>、id: select查詢的序列號,包含一組數字,表示查詢中執行select子句或操做表的順序python

  • id相同,執行順序由上至下
  • id不一樣,若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
  • id相同不一樣,同時存在。id若是相同,能夠認爲是一組,從上往下執行。

<2>、select_type:分別用來表示查詢的類型,主要是用於區別普通查詢、聯合查詢、子查詢等的複雜查詢。mysql

  • SIMPLE :簡單的select查詢,查詢中不包含子查詢或者UNION
  • PRIMARY :查詢中若包含任何複雜的子部分,最外層查詢則被標記爲PRIMARY
  • SUBQUERY :在SELECT或WHERE列表中包含了子查詢
  • DERIVED :在FROM列表中包含的子查詢被標記爲DERIVED(衍生),MySQL會遞歸執行這些子查詢,把結果放在臨時表中
  • UNION :若第二個SELECT出如今UNION以後,則被標記爲UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲:DERIVED
  • UNION RESULT :從UNION表獲取結果的SELECT

<3>、table:指的就是當前執行的表sql

<4>、type:顯示的是查詢使用了哪一種類型數據庫

  • system:表只有一行記錄(等於系統表),這是const類型的特列,平時不會出現,這個也能夠忽略不計
  • const:表示經過索引一次就找到了,const用於比較primary key 或者unique索引。由於只匹配一行數據,因此很快。如將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量。
    首先進行子查詢獲得一個結果的d1臨時表,子查詢條件爲id = 1 是常量,因此type是const,id爲1的至關於只查詢一條記錄,因此type爲system。
  • eq_ref:惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或惟一索引掃描。
  • ref:非惟一性索引掃描,返回匹配某個單獨值的全部行,本質上也是一種索引訪問,它返回全部匹配某個單獨值的行,然而,它可能會找到多個符合條件的行,因此他應該屬於查找和掃描的混合體。
  • range:只檢索給定範圍的行,使用一個索引來選擇行,key列顯示使用了哪一個索引,通常就是在你的where語句中出現between、< 、>、in等的查詢,這種範圍掃描索引比全表掃描要好,由於它只須要開始於索引的某一點,而結束於另外一點,不用掃描所有索引。
  • index:Full Index Scan,Index與All區別爲index類型只遍歷索引樹。這一般比ALL快,由於索引文件一般比數據文件小。(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤讀取的)
    id是主鍵,因此存在主鍵索引
  • all:Full Table Scan 將遍歷全表以找到匹配的行

從最好到最差依次是:system > const > eq_ref > ref > range > index > all。通常來講,得保證查詢至少達到range級別,最好能達到ref。vim

<5>、possible_keys:顯示可能應用在這張表中的索引,一個或多個。查詢涉及到的字段上若存在索引,則該索引將被列出,但不必定被查詢實際使用。服務器

<6>、key:實際使用的索引,若是爲NULL,則沒有使用索引。(可能緣由包括沒有創建索引或索引失效)。查詢中若使用了覆蓋索引(select 後要查詢的字段恰好和建立的索引字段徹底相同),則該索引僅出如今key列表中。性能

<7>、key_len:表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度,在不損失精確性的狀況下,長度越短越好。key_len顯示的值爲索引字段的最大可能長度,並不是實際使用長度,即key_len是根據表定義計算而得,不是經過表內檢索出的。測試

<8>、ref:顯示索引的那一列被使用了,若是可能的話,最好是一個常數。哪些列或常量被用於查找索引列上的值。優化

<9>、rows:根據表統計信息及索引選用狀況,大體估算出找到所需的記錄所須要讀取的行數,也就是說,用的越少越好。

<10>、包含不適合在其餘列中顯式但十分重要的額外信息。

​ 關於 explain 命令的具體用法和字段含義能夠參考官網explain-output

須要強調 rows 是核心指標,絕大部分 rows 小的語句執行必定很快(也有例外)。因此優化語句基本上都是在優化rows。

執行計劃:讓mysql預估執行操做(通常正確)
    all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
    id,email
    
    慢:
        select * from test where name='cai'
        
        explain select * from test where name='cai'
        type: ALL(全表掃描)
            select * from test limit 1;
    快:
        select * from test where email='cai@'
        type: const(走索引)

二、慢查詢優化的基本步驟

0.先運行看看是否真的很慢,注意設置 SQL_NO_CACHE
1.where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每一個字段分別查詢,看哪一個字段的區分度最高
2.explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢)
3.order by limit 形式的sql語句讓排序的表優先查
4.瞭解業務方使用場景
5.加索引時參照建索引的幾大原則
6.觀察結果,不符合預期繼續從0分析

三、慢日誌管理

​ MySQL的慢查詢日誌是MySQL提供的一種日誌記錄,它用來記錄在MySQL中響應時間超過閥值的語句,具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢日誌中。long_query_time的默認值爲10,意思是運行10S以上的語句。默認狀況下,Mysql數據庫並不啓動慢查詢日誌,須要手動來設置這個參數,固然,若是不是調優須要的話,通常不建議啓動該參數,由於開啓慢查詢日誌會或多或少帶來必定的性能影響。慢查詢日誌支持將日誌記錄寫入文件,也支持將日誌記錄寫入數據庫表。

# 慢日誌
    - 執行時間 > 10
    - 未命中索引
    - 日誌文件路徑

# 配置:
    - 內存
        show variables like '%query%';
        show variables like '%queries%';
        set global 變量名 = 值
    - 配置文件
    	mysqld --defaults-file='E:\cai\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini'

# my.conf內容:
    slow_query_log = ON
    slow_query_log_file = D:/....

# 注意:修改配置文件以後,須要重啓服務

四、MySQL日誌管理

(1)、MySQL日誌

#========================================================
錯誤日誌: 記錄 MySQL 服務器啓動、關閉及運行錯誤等信息
二進制日誌: 又稱binlog日誌,以二進制文件的方式記錄數據庫中除 SELECT 之外的操做
查詢日誌: 記錄查詢的信息
慢查詢日誌: 記錄執行時間超過指定時間的操做
中繼日誌: 備庫將主庫的二進制日誌複製到本身的中繼日誌中,從而在本地進行重放
通用日誌: 審計哪一個帳號、在哪一個時段、作了哪些事件
事務日誌或稱redo日誌: 記錄Innodb事務相關的如事務執行時間、檢查點等
#========================================================

(2)、MySQL日誌配置

## 1、bin-log
1. 啓用
# vim /etc/my.cnf
[mysqld]
log-bin[=dir\[filename]]
# service mysqld restart
2. 暫停
//僅當前會話
SET SQL_LOG_BIN=0;
SET SQL_LOG_BIN=1;
3. 查看
查看所有:
# mysqlbinlog mysql.000002
按時間:
# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56"
# mysqlbinlog mysql.000002 --stop-datetime="2012-12-05 11:02:54"
# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" --stop-datetime="2012-12-05 11:02:54" 

按字節數:
# mysqlbinlog mysql.000002 --start-position=260
# mysqlbinlog mysql.000002 --stop-position=260
# mysqlbinlog mysql.000002 --start-position=260 --stop-position=930
4. 截斷bin-log(產生新的bin-log文件)
a. 重啓mysql服務器
b. # mysql -uroot -p123 -e 'flush logs'
5. 刪除bin-log文件
# mysql -uroot -p123 -e 'reset master' 


## 2、查詢日誌
啓用通用查詢日誌
# vim /etc/my.cnf
[mysqld]
log[=dir\[filename]]
# service mysqld restart

## 3、慢查詢日誌
啓用慢查詢日誌
# vim /etc/my.cnf
[mysqld]
log-slow-queries[=dir\[filename]]
long_query_time=n
# service mysqld restart
MySQL 5.6:
slow-query-log=1
slow-query-log-file=slow.log
long_query_time=3  單位爲秒
查看慢查詢日誌
測試:BENCHMARK(count,expr)
SELECT BENCHMARK(50000000,2*3);
相關文章
相關標籤/搜索