MySQL分析與整理 — 日誌

2020-08-10 01:28:35

在这里插入图片描述

文章中所有操作均是在 MySQL 5.7 版本下進行的

無論是哪種數據庫,一定會有日誌檔案。在 MySQL 中主要有 5 種日誌檔案:

  1. 錯誤日誌,記錄 MySQL 服務的啓停時正確和錯誤的資訊,還記錄啓動、停止、執行過程中的錯誤資訊。
  2. 查詢日誌,記錄建立的用戶端連線和執行的語句。
  3. 二進制日誌,記錄所有更改數據的語句,可用於數據複製。
  4. 慢查詢日誌,記錄所有執行時間超過 long_query_time 的所有查詢或不使用索引的查詢。
  5. 中繼日誌,主從複製時使用的日誌。

官網也有相應的關於日誌的介紹:https://dev.mysql.com/doc/refman/5.7/en/server-logs.html

1 日誌的重新整理操作

-- sql命令
flush logs;
或者利用MySQL的mysqladmin命令(bin目錄下)
mysqladmin flush-logs
mysqladmin refresh

通過以上操作會重新整理日誌檔案,重新整理日誌檔案時會關閉舊的日誌檔案並重新開啓日誌檔案。對於有些日誌型別,如二進制日誌,重新整理日誌會卷動日誌檔案,而不僅僅是關閉並重新開啓。

2 錯誤日誌

錯誤日誌是最重要的日誌之一,並且錯誤日誌預設是啓用的。它記錄了 MySQL 服務啓動和停止正確和錯誤的資訊,還記錄了 mysqld 範例執行過程中發生的錯誤事件資訊。

log-error=file_name
在my.ini(my.cnf)中使用上面命令來指定mysqld記錄的錯誤日誌檔案,需要重新啓動MySQL服務生效
預設的錯誤日誌檔案爲data目錄下
file_name的預設名爲hostname.err,hostname表示當前的主機名
-- 檢視錯誤日誌的位置
show variables like '%log_error';
+---------------+---------------------------------------------------------------+
| Variable_name | Value                                                         |
+---------------+---------------------------------------------------------------+
| log_error     | D:\program1\MySQL\mysql-5.7.30-winx64\data\PC202002021713.err |
+---------------+---------------------------------------------------------------+
-- 以上是我本機的錯誤日誌位置

在錯誤日誌中還有個變數 log_warnings,其作用是表示警告資訊是否一併記錄到錯誤日誌中。

show variables like '%log_warnings';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_warnings  | 2     |
+---------------+-------+
/*
該值爲0,表示不記錄警告資訊。
該值爲1,表示警告資訊一併記錄到錯誤日誌中。
該值大於1,表示「失敗的連線」的資訊和建立新連線時「拒絕存取」類的錯誤資訊也會被記錄到錯誤日誌中。
*/

關於 log_warnings 這個變數,在 MySQL 5.6 中,log_warnings 的預設值爲1。在 MySQL 5.7 中,有的版本預設值是2,有些版本預設值是1,具體的情況下還得參考官方文件裡的資訊。可以在 my.ini(my.cnf)中使用 log_warnings 命令來指定是否記錄警告資訊。從 MySQL 5.7.2開始,官方推薦首選用 log_error_verbosity 變數替代 log_warnings ,在 MySQL 8.0.3 之後也被移除了。log_error_verbosity 的值有三個:1代表錯誤資訊,2代表錯誤資訊和告警資訊,3包括錯誤資訊、告警資訊和通知資訊。具體的還需要參考官網文件。

show variables like '%log_error_verbosity';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| log_error_verbosity | 3     |
+---------------------+-------+
-- 以上是我本機環境的log_error_verbosity預設值

隨着錯誤日誌的增加會越滾越大,可以先將舊的錯誤日誌進行備份(便於日後分析之用,Windows 和 Linux 操作不同就不演示了),然後生成新的錯誤日誌。可用 mysqladmin 或者是在 MySQL 用戶端中用 flush logs 來生成新的日誌,但是要注意這個操作還會重新整理二進制日誌。

3 一般查詢日誌

查詢日誌分爲「一般查詢日誌」和」慢查詢日誌「,它們是通過查詢是否超出變數 long_query_time 指定時間的值來判定的。在超時時間內完成的查詢是一般查詢,可以將其記錄到一般查詢日誌中,超出時間的查詢是慢查詢,可以將其記錄到慢查詢日誌中。一般情況下,一般的操作是相對應的正常數據操作,所以都是關閉一般查詢日誌(預設是關閉的)。

和查詢日誌相關的幾個系統變數:

long_query_time=10
log_output=[FILE|TABLE|NONE]
在my.ini(my.cnf)中使用上面命令來指定查詢日誌相關設定,需要重新啓動MySQL服務生效
  • long_query_time,指定慢查詢超時時長,超出此時長的屬於慢查詢,會記錄到慢查詢日誌中,預設 10,單位秒。
  • log_output,定義一般查詢日誌和慢查詢日誌的輸出格式,不指定時預設爲 FILE。log_output=TABLE表示記錄日誌到mysql 的 gengera_log 表中,該表的預設引擎是 CSV。log_output=NONE 表示不記錄日誌,指定爲 NONE,即使開啓了一般查詢日誌和慢查詢日誌,也都不會有任何記錄。
show variables like '%long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
show variables like '%log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+
-- 以上是我本機的預設設定

和一般查詢日誌相關的幾個變數:

general_log=[OFF|0|ON|1]
sql_log_off=[OFF|0|ON|1]
general_log_file=file_name
在my.ini(my.cnf)中使用上面命令來指定一般查詢日誌相關設定,需要重新啓動MySQL服務生效
  • general_log,是否啓用一般查詢日誌,預設是關閉 off。general_log 如果是在 MySQL 終端中進行設定,它是一個全域性變數,必須在 global 上修改。
  • sql_log_off,在session級別控制是否啓用一般查詢日誌,預設爲off,即啓用。sql_log_off 前提是 general_log 已啓用。
  • general_log_file,是指定日誌檔案的位置,預設在data目錄下。預設名爲 hostname.err,hostname 表示當前的主機名。
show variables like '%general_log';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| general_log   | OFF   |
+---------------+-------+
show variables like '%general_log_file';
+------------------+---------------------------------------------------------------+
| Variable_name    | Value                                                         |
+------------------+---------------------------------------------------------------+
| general_log_file | D:\program1\MySQL\mysql-5.7.30-winx64\data\PC202002021713.log |
+---------------+------------------------------------------------------------------+
-- 以上是我本機的一般查詢日誌預設設定

之前描述過,預設沒有開啓一般查詢日誌,也不建議開啓一般查詢日誌。這裏我們開啓測試一下看看是如何記錄一般查詢日誌的。

-- 開啓一般查詢日誌「set @@global.general_log = 1」也可以
set @@global.general_log = on;
show variables like '%general_log';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| general_log   | ON    |
+---------------+-------+
-- 隨便執行幾個語句
select host, user from mysql.user;
show variables like '%log_error%';
use test0;							-- 我本機有的測試庫
create table tbl_test3(id int);

這個時候會在相應的日誌檔案中看到相關的日誌內容:

2020-08-09T11:25:05.540000Z	    3 Query	select host, user from mysql.user
2020-08-09T11:25:11.150000Z	    3 Query	show variables like '%log_error%'
2020-08-09T11:25:34.860000Z	    3 Query	SELECT DATABASE()
2020-08-09T11:25:34.861000Z	    3 Init DB	test0
2020-08-09T11:25:37.285000Z	    3 Query	create table tbl_test3(id int)

我們再測試一下 sql_log_off 的作用(前提得開啓 general_log)。

-- 進入我本機的一個測試庫
use test0;
-- sql_log_off的狀態,預設是off或0
show variables like '%sql_log_off';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_off   | OFF   |
+---------------+-------+
create table tbl_test_1(id int);
insert into tbl_test_1 values (1001);
select * from tbl_test_1;
drop table tbl_test_1;
相應的日誌檔案中會出現剛纔的操作記錄
2020-08-09T11:34:13.981000Z	    3 Query	create table tbl_test_1(id int)
2020-08-09T11:34:19.398000Z	    3 Query	insert into tbl_test_1 values (1001)
2020-08-09T11:34:43.085000Z	    3 Query	select * from tbl_test_1
2020-08-09T11:34:48.172000Z	    3 Query	drop table tbl_test_1
-- 將sql_log_off設定爲on或1
 set sql_log_off = on;
 show variables like '%sql_log_off';
 +---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_log_off   | ON    |
+---------------+-------+
-- 之前的操作再來一遍
create table tbl_test_1(id int);
insert into tbl_test_1 values (1001);
select * from tbl_test_1;
drop table tbl_test_1;

這個時候會發現在日誌檔案中除了記錄了修改 sql_log_off 的操作,其它的操作都沒有進行記錄。所以 sql_log_off 的作用是什麼很明顯了。sql_log_off 是控制是否記錄到通用操作(create,insert,update,delete,select,drop等等)日誌,sql_log_off 預設是 off 狀態,不能理解爲「關閉」,應該是叫「開啓」這個記錄功能。

最後再囉嗦一句吧,一般查詢日誌最好關閉,它預設也是關閉的。而且,**一般查詢日誌中的「查詢」,並不是通常理解的 select 語句,幾乎所有的操作語句都會記錄。**這就是爲什麼它預設是關閉的大概原因所在吧。

4 慢查詢日誌

慢查詢日誌是超出變數「long_query_time」指定時間值,被認爲慢查詢。但是查詢獲取鎖(包括鎖等待)的時間不計入查詢時間內。MySQL 記錄慢查詢日誌是在查詢執行完畢且已經完全釋放鎖之後才記錄的,因此慢查詢日誌記錄的順序和執行的 SQL 查詢語句順序可能會不一致,比如語句 A 先執行,查詢速度慢,語句 B 後執行,但查詢速度較快,則語句 A 先記錄,當前前提下這倆語句都滿足慢查詢。

和慢查詢日誌相關的幾個變數:

long_query_time=10
log_output=[FILE|TABLE|NONE]
log_slow_queries=[YES|NO]
slow_query_log=[1|ON|0|OFF]
slow_query_log_file=hostname-slow.log
log_queries_not_using_indexes=[OFF|ON]
在my.ini(my.cnf)中使用上面命令來指定慢查詢日誌相關設定,需要重新啓動MySQL服務生效
  • long_query_time,指定慢查詢超時時長,超出此時長的屬於慢查詢,會記錄到慢查詢日誌中,預設 10,單位秒。
  • log_output,定義一般查詢日誌和慢查詢日誌的輸出格式,不指定時預設爲 FILE。log_output=TABLE表示記錄日誌到mysql 的 gengera_log 表中,該表的預設引擎是 CSV。log_output=NONE 表示不記錄日誌,指定爲 NONE,即使開啓了一般查詢日誌和慢查詢日誌,也都不會有任何記錄。
  • log_slow_queries,是否啓用慢查詢日誌,預設不啓用。如果是在 MySQL 終端中進行設定,它是一個全域性變數,必須在 global 上修改。這個變數不常用。
  • slow_query_log,也是是否啓用慢查詢日誌,此變數和上面的 log_slow_queries 修改一個另一個同時跟着變化。如果是在 MySQL 終端中進行設定,它是一個全域性變數,必須在 global 上修改。
  • slow_query_log_file,是指定慢查詢日誌檔案的位置,預設在data目錄下。預設名爲 hostname-slow.log,hostname 表示當前的主機名。
  • log_queries_not_using_indexes,查詢如果沒有使用索引的時候是否也記入慢查詢日誌。
show variables like '%slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+
show variables like '%slow_query_log_file';
+---------------------+----------------------------------------------------------------------+
| Variable_name       | Value                                                                |
+---------------------+----------------------------------------------------------------------+
| slow_query_log_file | D:\program1\MySQL\mysql-5.7.30-winx64\data\PC202002021713-slow.log |
+---------------------+----------------------------------------------------------------------+
-- 以上是我本機的慢查詢日誌預設設定

測試一下慢查詢的相關操作。

-- 開啓慢查詢日誌
set @@global.slow_query_log = on;
show variables like '%slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | ON    |
+----------------+-------+
-- 因爲預設的是10秒的超時時長,我們進行一個強制10+秒的操作
select sleep(11);
相應的慢查詢檔案中會出現剛纔的操作記錄
# Time: 2020-08-09T12:29:58.901000Z
# User@Host: root[root] @ localhost [::1]  Id:     3
# Query_time: 11.000000  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 0
use test0;
SET timestamp=1596976198;
select sleep(11);

隨着時間的推移,慢查詢日誌檔案中的記錄可能會變得非常多,這對於分析查詢來說是非常困難的,MySQL 數據庫提供一個「mysqldumpslow.pl」命令(在 bin 目錄中),因爲它是一個 perl 程式,需要相應的 perl 編譯器才能 纔能使用「mysqldumpslow.pl」命令。它的用途就是將慢查詢日誌檔案按照不同類型和要求分析,這裏就不在進行闡述了,可以在作者相關的文章中進行檢視和討論。

最後慢查詢日誌的時間支援微秒級的慢查詢超時時長,對於 DBA 來說,一個查詢執行 0.5 秒和執行 0.05 秒是非常不同的,前者可能索引使用錯誤或者走了表掃描,後者可能索引就使用正確。

5 二進制日誌

5.1 二進制日誌檔案

二進制日誌包含了引起或可能引起數據庫改變(如 delete 語句但沒有匹配行)的事件資訊,但絕不會包括 select 和 show 這樣的查詢語句。語句以「事件」的形式儲存,所以包含了時間、事件開始和結束位置等資訊。二進制日誌是以事件形式記錄的,不是事務日誌,不代表它只記錄 InnoDB 日誌,MyISAM 的表也一樣有二進制日誌。一個事務中可能包含多條二進制日誌事件,它們會在提交時一次性寫入。而對於非事務表的操作,每次執行完語句就直接寫入。

MySQL 預設下是沒有啓動二進制日誌,要啓用二進制日誌使用「log-bin=[on|off|file_name] 」選項指定,如果沒有給定 file_name,預設在 data 目錄下的主機名加「-bin」,並在後面跟上一串數位表示日誌序列號,如果給定的日誌檔案中包含了後綴(比如 logname.suffix 形式的)將忽略後綴部分。

開啓二進制日誌,找到 MySQL 的組態檔 my.ini(my.cnf),在 [mysqld] 最後加入以下程式碼:

log-bin=mysql-logbin
binlog-format=statement
server-id=1

設定結束儲存,重新啓動MySQL服務。當然還可以通過「set sql_log_bin = 1;」開啓,不過伺服器重新啓動它就失效了。以上設定參數解釋:

  • log-bin=mysql-logbin,其中「mysql-logbin」是自定義的二進制檔名(可根據要求自定義),」log-bin=「後是可以指定 path 路徑的,不指定預設是爲 MySQL 的 data 目錄。二進制檔名也可以不用定義,預設會以主機名生成日誌清單。
  • binlog-format,日誌記錄格式。(statement | row | mixed),statement 是以最初基於 SQL 語句日誌記錄日誌,row 表始終使用主鍵以確保行可以有效的標識,mixed 是兼顧前兩者的混合日誌記錄。
  • server-id=1,MySQL5.7+ 如果開啓了二進制日誌,則 server-id 必須指定,否則會不允許服務啓動。server-id 具體可以幹什麼用的以後文章會提到,這裏不細討論了。
  • 還有其它幾個設定參數,**expire_logs_days **和 max_binlog_size。**expire_logs_days **是用來定義了 MySQL 清除過期日誌的時間,即二進制日誌自動刪除的天數,預設值爲0,表示不自動刪除。max_binlog_size定義了單個檔案的大小限制,如果二進制日誌寫入的內容大小超出給定值,日誌就會發生回滾(關閉當前檔案,重新開啓一個新的日誌檔案)。預設1GB, 不能大於1GB或小於4096B。

重新啓動 MySQL 服務之後會在 MySQL 目錄的 data 目錄下生成兩個檔案:

mysql-logbin.000001
mysql-logbin.index

其中「mysql-logbin.000001」檔案是二進制日誌檔案的操作記錄檔案,「mysql-logbin.index」是二進制日誌索引檔案,索引檔案中包含所有使用的二進制日誌檔案的檔名。預設情況下該檔案與二進制日誌檔案的檔名相同,擴充套件名爲「.index」。要指定該檔案的檔名使用「log-bin-index[=file_name] 」選項(爲了和記錄檔名保持相應的一致性,一般情況下不去修改)。

二進制日誌檔案當寫入的內容大小超出給定值(預設 1 GB),日誌就會發生回滾(關閉當前檔案,重新開啓一個新的日誌檔案),或者使用者強制執行了日誌重新整理操作,二進制日誌也會發生回滾。這個時候就會生成新的二進制日誌記錄檔案,比如我本機的測試狀態下,重新整理日誌操作之後:

mysql-logbin.000002
mysql-logbin.000001
mysql-logbin.index

5.2 檢視二進制日誌

5.2.1 使用mysqlbinlog命令

mysqlbinlog 在 MySQL 安裝目錄的 bin 目錄下,它的命令格式如下:

mysqlbinlog [option] log-file1 log-file2...
option的幾個常用選項
-d,--database=name:只檢視指定數據庫的日誌操作
-o,--offset=#:忽略掉日誌中的前n個操作命令
-r,--result-file=name:將輸出的日誌資訊輸出到指定的檔案中,使用重定向也一樣可以。
-s,--short-form:顯示簡單格式的日誌,只記錄一些普通的語句,會省略掉一些額外的資訊如位置資訊和時間資訊以及基於行的日誌。可以用來偵錯,生產環境千萬不可使用
--set-charset=char_name:在輸出日誌資訊到檔案中時,在檔案第一行加上set names char_name
--start-datetime,--stop-datetime:指定輸出開始時間和結束時間內的所有日誌資訊
--start-position=#,--stop-position=#:指定輸出開始位置和結束位置內的所有日誌資訊
-v,-vv:顯示更詳細資訊,基於row的日誌預設不會顯示出來,此時使用-v或-vv可以檢視

在進行測試之前,我這裏先對日誌進行一次重新整理操作,方便後續的演示。

mysqladmin -uroot -p refresh
mysqlbinlog ../data/mysql-logbin.000001
以上檢視日誌檔案,請注意日誌檔案的位置和命名
這裏是我本機的位置和命名
因爲mysqlbinlog在bin目錄,日誌檔案在data目錄

檢視「mysql-logbin.000001」二進制日誌檔案內容如下:

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#200809 23:44:06 server id 1  end_log_pos 123 CRC32 0xaf3f2d31  Start: binlog v 4, server v 5.7.30-log created 200809 23:44:06 at startup
ROLLBACK/*!*/;
BINLOG '
xhkwXw8BAAAAdwAAAHsAAAAAAAQANS43LjMwLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADGGTBfEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQAATEtP68=
'/*!*/;
# at 123
#200809 23:44:06 server id 1  end_log_pos 154 CRC32 0xba4c6aab  Previous-GTIDs
# [empty]
# at 154
#200809 23:51:09 server id 1  end_log_pos 204 CRC32 0x9fb0e6df  Rotate to mysql-logbin.000002  pos: 4
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

因爲我剛剛開啓了二進制日誌記錄功能,也沒有任何操作,裏面暫時只有一些初始資訊,沒有記錄任何操作過的記錄。雖然內容看起來比較凌亂但是我們可以清楚的看到「at 4」和「Rotate to mysql-logbin.000002」字眼,其中「at 4」和下面 下麪的一些資訊,記錄了時間和位置資訊,「Rotate to mysql-logbin.000002」更好理解,產生了新的日誌記錄檔案。

繼續測試,現在在現有的數據庫中執行幾個簡單的操作:

use test0;	-- 作者本機就有的測試數據庫
create table tbl_stu (id int primary key,name varchar(10) not null);
alter table tbl_stu add column age int;
insert into tbl_stu values(1,'小明',16),(2,'小王',12);

因爲剛纔重新整理了二進制日誌,所以 MySQL 會在「mysql-logbin.000002」進行操作日誌的記錄,我們檢視一下這個檔案:

mysqlbinlog ../data/mysql-logbin.000002

由於日誌比較內容較多,我對輸出的內容進行了整理,貼出我們需要討論的內容:

# at 219
#200810  0:09:45 server id 1  end_log_pos 362 CRC32 0x2ab759f7  Query   thread_id=3     exec_time=0     error_code=0
use `test0`/*!*/;
SET TIMESTAMP=1596989385/*!*/;
SET @@session.pseudo_thread_id=3/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549120/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table tbl_stu (id int primary key,name varchar(10) not null)/*!*/;

# at 427
#200810  0:09:50 server id 1  end_log_pos 541 CRC32 0x2790b4b5  Query   thread_i
d=3     exec_time=0     error_code=0
SET TIMESTAMP=1596989390/*!*/;
alter table tbl_stu add column age int/*!*/;

# at 606
#200810  0:09:56 server id 1  end_log_pos 687 CRC32 0x2d0526cf  Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1596989396/*!*/;
BEGIN
# at 687
#200810  0:09:56 server id 1  end_log_pos 820 CRC32 0xec31dc19  Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1596989396/*!*/;
insert into tbl_stu values(1,'小明',16),(2,'小王',12)/*!*/;
# at 820
#200810  0:09:56 server id 1  end_log_pos 851 CRC32 0x5b900093  Xid = 9 COMMIT/*!*/;

仔細看可以找到我們剛纔執行的幾個操作,其中「at」字眼是操作的位置碼,緊接着「at」下面 下麪的時間就是操作的時間點。從上面的日誌還可以看到,「insert」操作之前和之後還啓動的事務和事務提交,所以我們剛纔測試的幾個操作,一共執行了6個操作(use database,create table,alter table,begin,insert,commit)。

mysqlbinlog 還有其它的幾個操作:

  • 使用 -r 命令將日誌檔案匯入到指定檔案中。

    mysqlbinlog ../data/mysql-logbin.000002 -r /xxx/binlog.000002
    
  • 使用 -s 命令將日誌檔案簡化到到指定檔案中。

    mysqlbinlog ../data/mysql-logbin.000002 -s>/xxx/binlog.sample
    
  • 使用 -o 可以忽略前 N 個條目,比如剛纔的測試操作,有 6 個操作,我們可以忽略掉前三個。

    mysqlbinlog ../data/mysql-logbin.000002 -o 3
    
  • 使用 -d 可以只顯示指定數據庫相關的操作,比如剛纔的是使用的「test0」數據庫。

    mysqlbinlog ../data/mysql-logbin.000002 -d test0
    

二進制日誌檔案中,最重要的有兩個資訊,一個就是「at xxx」位置點和之後的時間點,mysqlbinlog 命令檢視二進制日誌檔案時可以分別指定位置區間和時間區間,如下:

mysqlbinlog ../data/mysql-logbin.000002 --start-datetime='2020-08-09 23:59:59' --stop-datetime='2020-08-10 00:09:50'

mysqlbinlog ../data/mysql-logbin.000002 --start-position=427 --stop-position=820

由於篇幅問題,上面的命令就不挨個進行貼內容了,如有興趣請您自行嘗試。

5.2.2 show binary logs語句

該語句用於檢視當前使用了哪些二進制日誌檔案,可以通過檢視二進制的 index 檔案來檢視當前正在使用哪些二進制日誌,如下:

show binary logs;
+---------------------+-----------+
| Log_name            | File_size |
+---------------------+-----------+
| mysql-logbin.000001 |       204 |
| mysql-logbin.000002 |       851 |
+---------------------+-----------+
-- 以上我本機的測試環境內容
5.2.3 show binlog events語句
-- 檢視指定的二進制日誌檔案
show binlog events in 'mysql-logbin.000002';
+---------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------+
| Log_name            | Pos | Event_type     | Server_id | End_log_pos | Info                                                                             |
+---------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------+
| mysql-logbin.000002 |   4 | Format_desc    |         1 |         123 | Server ver: 5.7.30-log, Binlog ver: 4                                            |
| mysql-logbin.000002 | 123 | Previous_gtids |         1 |         154 |                                                                                  |
| mysql-logbin.000002 | 154 | Anonymous_Gtid |         1 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                             |
| mysql-logbin.000002 | 219 | Query          |         1 |         362 | use `test0`; create table tbl_stu (id int primary key,name varchar(10) not null) |
| mysql-logbin.000002 | 362 | Anonymous_Gtid |         1 |         427 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                             |
| mysql-logbin.000002 | 427 | Query          |         1 |         541 | use `test0`; alter table tbl_stu add column age int                              |
| mysql-logbin.000002 | 541 | Anonymous_Gtid |         1 |         606 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                             |
| mysql-logbin.000002 | 606 | Query          |         1 |         687 | BEGIN                                                                            |
| mysql-logbin.000002 | 687 | Query          |         1 |         820 | use `test0`; insert into tbl_stu values(1,'小明',16),(2,'小王',12)               |
| mysql-logbin.000002 | 820 | Xid            |         1 |         851 | COMMIT /* xid=9 */                                                               |
+---------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------+
-- 可以增加位置篩選
show binlog events in 'mysql-logbin.000002' from 427;
+---------------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------+
| Log_name            | Pos | Event_type     | Server_id | End_log_pos | Info                                                                   |
+---------------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------+
| mysql-logbin.000002 | 427 | Query          |         1 |         541 | use `test0`; alter table tbl_stu add column age int                    |
| mysql-logbin.000002 | 541 | Anonymous_Gtid |         1 |         606 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                   |
| mysql-logbin.000002 | 606 | Query          |         1 |         687 | BEGIN                                                                  |
| mysql-logbin.000002 | 687 | Query          |         1 |         820 | use `test0`; insert into tbl_stu values(1,'小明',16),(2,'小王',12)     |
| mysql-logbin.000002 | 820 | Xid            |         1 |         851 | COMMIT /* xid=9 */                                                     |
+---------------------+-----+----------------+-----------+-------------+------------------------------------------------------------------------+
5.2.4 show master status語句

該語句用於顯示主伺服器中的二進制日誌資訊。如果是主從結構,它只會顯示主從結構中主伺服器的二進制日誌資訊。它可以檢視到當前正在使用的日誌及下一事件記錄的開始位置,還能檢視到哪些數據庫需要記錄二進制日誌,哪些數據庫不記錄二進制日誌。如下:

show master status;
+---------------------+----------+--------------+------------------+-------------------+
| File                | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------+----------+--------------+------------------+-------------------+
| mysql-logbin.000002 |      851 |              |                  |                   |
+---------------------+----------+--------------+------------------+-------------------+

5.3 刪除二進制日誌

-- 刪除所有日誌,並讓日誌檔案重新從000001開始(慎用)
reset master;
-- 清空000002之前的所有日誌檔案,master和binary都可以(慎用)
purge master logs to "mysql-logbin.000002";
purge binary logs to "mysql-logbin.000002";
/*
purge master logs before 'yyyy-mm-dd hh:mi:ss'
刪除指定日期之前的所有日誌
但是若指定的時間處在正在使用中的日誌檔案中,將無法進行purge。
(慎用)
*/
purge master logs before '2020-08-10 00:11:1';

5.4 二進制日誌其它相關的變數

  • log_bin = [on|off|file_name],指定是否啓用記錄二進制日誌或者指定一個日誌路徑,且路徑不能加「.」點,否則點後的被忽略。
  • sql_log_bin = [on|off],指定是否啓用記錄二進制日誌,只有在 log_bin 開啓的時候纔有效。
  • expire_logs_days,指定自動刪除二進制日誌的時間,即日誌過期時間。
  • binlog_do_db,明確指定要記錄日誌的數據庫。
  • binlog_ignore_db,指定不記錄二進制日誌的數據庫。
  • log_bin_index,指定 mysql-bin.index 檔案的路徑。
  • binlog_format = [mixed|row|statement],指定二進制日誌基於什麼模式記錄。
  • binlog_rows_query_log_events = [1|0], MySQL 5.6.2新增了該變數,當binlog_format 爲 row 時,預設不會記錄 row 對應的 SQL 語句,設定爲 1 時會記錄,但需要使用 mysqlbinlog -v 檢視,這些語句是被註釋的,恢復時不會被執行。
  • max_binlog_size,指定二進制日誌檔案最大值,超出指定值將自動卷動。但由於事務不會跨檔案,所以並不一定總是精確。
  • binlog_cache_size,基於事務型別的日誌會先記錄在緩衝區,當達到該緩衝大小時這些日誌會寫入磁碟。
  • max_binlog_cache_size,指定二進制日誌快取最大大小,硬限制,預設4G,建議不要改。
  • binlog_cache_use,使用快取寫二進制日誌的次數。
  • binlog_cache_disk_use,使用臨時檔案寫二進制日誌的次數,當紀錄檔超過了 binlog_cache_size 的時候會使用臨時檔案寫日誌,如果該變數值不爲 0,則考慮增大 binlog_cache_size 的值。
  • binlog_stmt_cache_size,一般等同於且決定 binlog_cache_size 大小,所以修改快取大小時只需修改這個而不用修改 binlog_cache_size。
  • binlog_stmt_cache_use,使用快取寫二進制日誌的次數。
  • binlog_stmt_cache_disk_use,使用臨時檔案寫二進制日誌的次數,當紀錄檔超過了 binlog_cache_size 的時候會使用臨時檔案寫日誌,如果該變數值不爲 0,則考慮增大 binlog_cache_size 的值。
  • sync_binlog = [0|n],這個參數直接影響 mysql 的效能和完整性。sync_binlog =0 表示不同步,日誌何時刷到磁碟由 FileSystem 決定,這個效能最好。sync_binlog = n 表示每寫 n 次事務,MySQL 將執行一次磁碟同步指令 fdatasync() 將快取日誌重新整理到磁碟日誌檔案中。MySQL 中預設的設定是 sync_binlog = 0,即不同步,這時效能最好,但風險最大。一旦系統奔潰,快取中的日誌都會丟失。

5.5 二進制日誌還原數據庫

關於利用二進制日誌檔案還原數據庫的操作,在作者另外一篇文章「備份與恢復」中有詳細的操作和討論。

結語

除了這 5 種日誌,在需要的時候還會建立DDL日誌。上面只是討論了錯誤日誌、一般查詢日誌、慢查詢日誌和二進制日誌。其它的比如中繼日誌和主從複製有關,將在有關「MySQL 複製」的章節中介紹。

另外以上所有的操作都是在更改 MySQL 組態檔 my.ini(my.cnf)的基礎上講解的,所以需要重新啓動 MySQL 才能 纔能使設定生效,當然您可以通過在 MySQL 終端中通過改變全域性變數也可以進行設定這些操作,不過 MySQL 服務如果重新啓動了,這些設定就失效了。