1. 程式人生 > 資料庫 >詳解MySQL 慢查詢

詳解MySQL 慢查詢

查詢mysql的操作資訊

show status -- 顯示全部mysql操作資訊

show status like "com_insert%"; -- 獲得mysql的插入次數;

show status like "com_delete%"; -- 獲得mysql的刪除次數;

show status like "com_select%"; -- 獲得mysql的查詢次數;

show status like "uptime"; -- 獲得mysql伺服器執行時間

show status like 'connections'; -- 獲得mysql連線次數

查詢mysql的操作資訊show [session|global] status like .... 如果你不寫 [session|global] 預設是session 會話,只取出當前視窗的執行,如果你想看所有(從mysql 啟動到現在,則應該 global)

通過查詢mysql的讀寫比例,可以做相應的配置優化;

慢查詢

當Mysql效能下降時,通過開啟慢查詢來獲得哪條SQL語句造成的響應過慢,進行分析處理。當然開啟慢查詢會帶來CPU損耗與日誌記錄的IO開銷,所以我們要間斷性的開啟慢查詢日誌來檢視Mysql執行狀態。

慢查詢能記錄下所有執行超過long_query_time時間的SQL語句,用於找到執行慢的SQL,方便我們對這些SQL進行優化.

show variables like "%slow%";-- 是否開啟慢查詢;
show status like "%slow%"; -- 查詢慢查詢SQL狀況;
show variables like "long_query_time"; -- 慢查詢時間

慢查詢開啟設定

mysql> show variables like 'long_query_time'; -- 預設情況下,mysql認為10秒才是一個慢查詢
+-----------------+-----------+
| Variable_name  | Value   |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+

mysql> set long_query_time=1; -- 修改慢查詢時間,只能當前會話有效;
mysql> set global slow_query_log='ON';-- 啟用慢查詢,加上global,不然會報錯的;

也可以在配置檔案中更改
修改mysql配置檔案my.ini[windows]/my.cnf[Linux]加入,注意必須在[mysqld]後面加入

slow_query_log = on -- 開啟日誌;
slow_query_log_file = /data/f/mysql_slow_cw.log -- 記錄日誌的log檔案; 注意:window上必須寫絕對路徑,比如 D:/wamp/bin/mysql/mysql5.5.16/data/show-slow.log 
long_query_time = 2 -- 最長查詢的秒數;
log-queries-not-using-indexes -- 表示記錄沒有使用索引的查詢

使用慢查詢

Example1:

mysql> select sleep(3);

mysql> show status like '%slow%';
+---------------------+-------+
| Variable_name    | Value |
+---------------------+-------+
| Slow_launch_threads | 0   |
| Slow_queries    | 1   |
+---------------------+-------+
-- Slow_queries 一共有一條慢查詢

Example2:

利用儲存過程構建一個大的資料庫來進行測試;

資料準備

CREATE TABLE dept(
deptno MEDIUMINT  UNSIGNED NOT NULL DEFAULT 0 comment '編號',dname VARCHAR(20) NOT NULL DEFAULT "" comment '名稱',loc VARCHAR(13) NOT NULL DEFAULT "" comment '地點'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 comment '部門表' ;

CREATE TABLE emp
(empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,ename VARCHAR(20) NOT NULL DEFAULT "" comment '名字',job VARCHAR(9) NOT NULL DEFAULT "" comment '工作',mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 comment '上級編號',hiredate DATE NOT NULL comment '入職時間',sal DECIMAL(7,2) NOT NULL comment '薪水',comm DECIMAL(7,2) NOT NULL comment '紅利',deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 comment '部門編號' 
)ENGINE=MyISAM DEFAULT CHARSET=utf8 comment '僱員表';

CREATE TABLE salgrade(
grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 comment '等級',losal DECIMAL(17,2) NOT NULL comment '最低工資',hisal DECIMAL(17,2) NOT NULL comment '最高工資'
)ENGINE=MyISAM DEFAULT CHARSET=utf8 comment '工資級別表';

INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);

delimiter $
create function rand_num() 
returns tinyint(6) READS SQL DATA 
begin 
 declare return_num tinyint(6) default 0;
 set return_num = floor(1+rand()*30);
 return return_num;
end $

delimiter $
create function rand_string(n INT) 
returns varchar(255) READS SQL DATA 
begin 
 declare chars_str varchar(100) default
 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
 declare return_str varchar(255) default '';
 declare i int default 0;
 while i < n do 
  set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
  set i = i + 1;
 end while;
 return return_str;
end $

delimiter $
create procedure insert_emp(in start int(10),in max_num int(10))
begin
 declare i int default 0; 
 #set autocommit =0 把autocommit設定成0,關閉自動提交;
 set autocommit = 0; 
 repeat
  set i = i + 1;
  insert into emp values ((start+i),rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());
  until i = max_num
 end repeat;
 commit;
end $

call insert_emp(1,4000000);
SELECT * FROM `emp` where ename like '%mQspyv%'; -- 1.163s

# Time: 150530 15:30:58 -- 該查詢發生在2015-5-30 15:30:58
# User@Host: root[root] @ localhost [127.0.0.1] -- 是誰,在什麼主機上發生的查詢
# Query_time: 1.134065 Lock_time: 0.000000 Rows_sent: 8 Rows_examined: 4000000 
-- Query_time: 查詢總共用了多少時間,Lock_time: 在查詢時鎖定表的時間,Rows_sent: 返回多少rows資料,Rows_examined: 表掃描了400W行資料才得到的結果;
SET timestamp=1432971058; -- 發生慢查詢時的時間戳;
SELECT * FROM `emp` where ename like '%mQspyv%';

開啟慢查詢後每天都有可能有好幾G的慢查詢日誌,這個時候去人工的分析明顯是不實際的;

慢查詢分析工具:

mysqldumpslow

該工具是慢查詢自帶的分析慢查詢工具,一般只要安裝了mysql,就會有該工具;

Usage: mysqldumpslow [ OPTS... ] [ LOGS... ] -- 後跟引數以及log檔案的絕對地址;

 -s      what to sort by (al,at,ar,c,l,r,t),'at' is default 
        al: average lock time 
        ar: average rows sent
        at: average query time
        c: count 
        l: lock time
        r: rows sent
        t: query time

 -r      reverse the sort order (largest last instead of first)
 -t NUM    just show the top n queries
 -a      don't abstract all numbers to N and strings to 'S'
 -n NUM    abstract numbers with at least n digits within names
 -g PATTERN  grep: only consider stmts that include this string
 -h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard),default is '*',i.e. match all
 -i NAME   name of server instance (if using mysql.server startup script)
 -l      don't subtract lock time from total time

常見用法

mysqldumpslow -s c -t 10 /var/run/mysqld/mysqld-slow.log # 取出使用最多的10條慢查詢 

mysqldumpslow -s t -t 3 /var/run/mysqld/mysqld-slow.log # 取出查詢時間最慢的3條慢查詢

mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log # 得到按照時間排序的前10條裡面含有左連線的查詢語句

 mysqldumpslow -s r -t 10 -g 'left join' /var/run/mysqld/mysqld-slow.log # 按照掃描行數最多的

注意: 使用mysqldumpslow的分析結果不會顯示具體完整的sql語句,只會顯示sql的組成結構;

假如: SELECT * FROM sms_send WHERE service_id=10 GROUP BY content LIMIT 0,1000;
mysqldumpslow來顯示

Count: 1 Time=1.91s (1s) Lock=0.00s (0s) Rows=1000.0 (1000),vgos_dba[vgos_dba]@[10.130.229.196]
SELECT * FROM sms_send WHERE service_id=N GROUP BY content LIMIT N,N;

pt-query-digest

說明

pt-query-digest是用於分析mysql慢查詢的一個工具,它可以分析binlog、General log、slowlog,也可以通過SHOWPROCESSLIST或者通過tcpdump抓取的MySQL協議資料來進行分析。可以把分析結果輸出到檔案中,分析過程是先對查詢語句的條件進行引數化,然後對引數化以後的查詢進行分組統計,統計出各查詢的執行時間、次數、佔比等,可以藉助分析結果找出問題進行優化。
pt-query-digest是一個perl指令碼,只需下載並賦權即可執行。

安裝

wget http://www.percona.com/get/pt-query-digest 
chmod +x pt-query-digest
# 注意這是一個Linux指令碼,要指明絕對或相對路徑來使用

--或者下載整套工具

wget percona.com/get/percona-toolkit.rpm
rpm -ivh percona-toolkit-2.2.13-1.noarch.rpm

wget percona.com/get/percona-toolkit.tar.gz
tar -zxvf percona-toolkit-2.2.13.tar.gz 
cd percona-toolkit-2.2.13
perl Makefile.PL
make && make install

語法及重要選項

pt-query-digest [OPTIONS] [FILES] [DSN]

--create-review-table 當使用--review引數把分析結果輸出到表中時,如果沒有表就自動建立。
--create-history-table 當使用--history引數把分析結果輸出到表中時,如果沒有表就自動建立。
--filter 對輸入的慢查詢按指定的字串進行匹配過濾後再進行分析
--limit限制輸出結果百分比或數量,預設值是20,即將最慢的20條語句輸出,如果是50%則按總響應時間佔比從大到小排序,輸出到總和達到50%位置截止。
--host mysql伺服器地址
--user mysql使用者名稱
--password mysql使用者密碼
--history 將分析結果儲存到表中,分析結果比較詳細,下次再使用--history時,如果存在相同的語句,且查詢所在的時間區間和歷史表中的不同,則會記錄到資料表中,可以通過查詢同一CHECKSUM來比較某型別查詢的歷史變化。
--review 將分析結果儲存到表中,這個分析只是對查詢條件進行引數化,一個型別的查詢一條記錄,比較簡單。當下次使用--review時,如果存在相同的語句分析,就不會記錄到資料表中。
--output 分析結果輸出型別,值可以是report(標準分析報告)、slowlog(Mysql slow log)、json、json-anon,一般使用report,以便於閱讀。
--since 從什麼時間開始分析,值為字串,可以是指定的某個”yyyy-mm-dd [hh:mm:ss]”格式的時間點,也可以是簡單的一個時間值:s(秒)、h(小時)、m(分鐘)、d(天),如12h就表示從12小時前開始統計。
--until 截止時間,配合—since可以分析一段時間內的慢查詢。

第一部分:總體統計結果:

標準分析報告解釋

詳解MySQL 慢查詢

Overall: 總共有多少條查詢,上例為總共266個查詢。
Time range: 查詢執行的時間範圍。
unique: 唯一查詢數量,即對查詢條件進行引數化以後,總共有多少個不同的查詢,該例為4。
total: 總計 min:最小 max: 最大 avg:平均
95%: 把所有值從小到大排列,位置位於95%的那個數,這個數一般最具有參考價值。
median: 中位數,把所有值從小到大排列,位置位於中間那個數。

第二部分: 查詢分組統計結果:

詳解MySQL 慢查詢

這部分對查詢進行引數化並分組,然後對各類查詢的執行情況進行分析,結果按總執行時長,從大到小排序。
Response: 總的響應時間。
time: 該查詢在本次分析中總的時間佔比。
calls: 執行次數,即本次分析總共有多少條這種型別的查詢語句。
R/Call: 平均每次執行的響應時間。
Item : 查詢物件

第三部分:每一種查詢的詳細統計結果:

詳解MySQL 慢查詢

由上圖可見,1號查詢的詳細統計結果,最上面的表格列出了執行次數、最大、最小、平均、95%等各專案的統計。
Databases: 庫名
Users: 各個使用者執行的次數(佔比)
Query_time distribution : 查詢時間分佈,長短體現區間佔比,本例中1s-10s之間查詢數量沒有,全部集中在10S裡面。
Tables: 查詢中涉及到的表
Explain: 該條查詢的示例

用法示例

(1)直接分析慢查詢檔案:

pt-query-digest slow.log > slow_report.log

(2)分析最近12小時內的查詢:

pt-query-digest --since=12h slow.log > slow_report2.log

(3)分析指定時間範圍內的查詢:

pt-query-digest slow.log --since '2014-05-17 09:30:00' --until '2014-06-17 10:00:00'> > slow_report3.log

(4)分析只含有select語句的慢查詢

pt-query-digest --filter '$event->{fingerprint} =~ m/^select/i' slow.log> slow_report4.log

(5) 針對某個使用者的慢查詢

pt-query-digest --filter '($event->{user} || "") =~ m/^root/i' slow.log> slow_report5.log

(6) 查詢所有所有的全表掃描或full join的慢查詢

pt-query-digest --filter '(($event->{Full_scan} || "") eq "yes") ||(($event->{Full_join} || "") eq "yes")' slow.log> slow_report6.log

(7)把查詢儲存到test資料庫的query_review表,如果沒有的話會自動建立;

pt-query-digest --user=root –password=abc123 --review h=localhost,D=test,t=query_review --create-review-table slow.log

(8)把查詢儲存到query_history表

pt-query-digest --user=root –password=abc123 --review h=localhost,t=query_ history --create-review-table slow.log_20140401

(9)通過tcpdump抓取mysql的tcp協議資料,然後再分析

tcpdump -s 65535 -x -nn -q -tttt -i any -c 1000 port 3306 > mysql.tcp.txt
pt-query-digest --type tcpdump mysql.tcp.txt> slow_report9.log

(10)分析binlog

mysqlbinlog mysql-bin.000093 > mysql-bin000093.sql
pt-query-digest --type=binlog mysql-bin000093.sql > slow_report10.log

(11)分析general log

pt-query-digest --type=genlog localhost.log > slow_report11.log

以上就是詳解MySQL 慢查詢的詳細內容,更多關於MySQL 慢查詢的資料請關注我們其它相關文章!