1. 程式人生 > 實用技巧 >CF632F - Magic Matrix 題解

CF632F - Magic Matrix 題解

MySQL日誌記錄了MySQL資料庫日常操作和錯誤資訊。MySQL有不同型別的日誌檔案(各自儲存了不同型別的日誌),從日誌當中可以查詢到MySQL資料庫的執行情況、使用者的操作、錯誤的資訊等。

MySQL的日誌分為四大類:

  • 錯誤日誌:記錄MySQL服務的啟動、執行或停止MySQL服務時出現的問題;
  • 查詢日誌:記錄建立的客戶端的連線和執行的語句;
  • 二進位制日誌:記錄所有更改資料的語句,可以用於資料的複製;
  • 慢查詢日誌:記錄所有執行時間超過long_query_time的所有查詢或不使用索引的查詢;

預設情況下,所有日誌創建於MySQL資料目錄中,通過重新整理日誌,可以強制MySQL關閉或重新開啟日誌檔案,Flush logs

重新整理日誌或者執行mysqladmin flush-logs。如果正使用MySQL複製功能,在複製伺服器上可以維護更多日誌檔案,這種日誌我們成為接替日誌。啟動日誌功能會降低MySQL資料庫的效能。

查詢系統設定

mysql> show global variables\G
mysql> show global variables like '%log%';
#檢視全域性的系統狀態
mysql> show session variables\G
mysql> show session variables like '%log%';
#檢視當前會話的系統狀態

若要修改上面查看出來的引數,可以在MySQL的主配置檔案中的mysqld欄位中寫入即可,如:binlog_cache_size = 1M

。又或者可以在MySQL資料庫中進行臨時修改:set global binlog_cache_size = 1048576,這種臨時修改在MySQL重啟後就會失效。

檢視執行狀態

mysql> show global status\G
#檢視全域性的執行狀態
mysql> show session status;
#檢視當前會話的執行狀態
[root@mysql ~]# mysql -V
mysql> status;
mysql> select version();
#檢視MySQL的版本

一、錯誤日誌

在MySQL資料庫中,錯誤日誌功能是預設開啟的。預設情況下,錯誤日誌儲存在MySQL資料庫的資料目錄中。

錯誤日誌檔案通常的名稱為hostname.err,其中。hostname表示伺服器主機名。

錯誤日誌資訊可以自己進行配置的,錯誤日誌所記錄的資訊是可以通過log-errlog-warnings來定義的。其中log-err是定義是否啟用錯誤日誌的功能和錯誤日誌的儲存位置,log-warnings是定義是否將警告資訊也定義到錯誤日誌中。

預設情況下錯誤日誌大概記錄以下資訊:

  • 伺服器啟動和關閉過程中的資訊(未必是錯誤資訊,如mysql如何啟動InnoDB的表空間檔案的、如何初始化自己的儲存引擎等等資訊);
  • 服務執行過程中的錯誤資訊、時間排程器執行一個事件時產生的資訊;
  • 在從伺服器上啟動伺服器程序時產生的資訊;
  • MySQL有很多系統變數是可以設定,系統變數設定不同,會導致系統執行狀態的不同。因此mysql提供兩組命令,分別檢視系統設定和執行狀態;

1.1檢視錯誤日誌

一般而言,日誌級別的定義沒有會話變數都只是在全域性級別下定義錯誤日誌的狀態:

mysql> show global variables like '%log_error%';
+---------------------+----------------------------------+
| Variable_name       | Value                            |
+---------------------+----------------------------------+
| binlog_error_action | ABORT_SERVER                     |
| log_error           | /usr/local/mysql/data/mysqld.err |
| log_error_verbosity | 3                                |
+---------------------+----------------------------------+

其中,log_error定義錯誤日誌檔案路徑, log_error_verbosity值的含義如下:

Verbosity message
1 Error only
2 Error and warnings
3 Error、warnings、notes(defult)

1.2 定義錯誤日誌

錯誤日誌的存放路徑在mysql主配置檔案中指定,如下:

[root@db01 ~]# cat /etc/my.cnf
[mysqld]
log-error=/usr/local/mysql/data/mysqld.err

為了方便維護需要,有時會希望將錯誤日誌中的內容做備份並重新開始記錄,這時就可以利用MySQL的flush logs命令來告訴MySQL備份舊日誌並生成新的日誌檔案。備份檔名以“.old”結尾。

1.3 刪除錯誤日誌

在mysql 5.5版本之前,資料庫管理員可以刪除很長時間之前的錯誤日誌,來保證mysql伺服器上的硬碟空間。

mysql資料庫中,可以使用mysqladmin命令開啟新的錯誤日誌。mysqladmin命令的語法如下:mysqladmin –u root –p flush-logs也可以登入mysql資料庫中使用FLUSH LOGS語句來開啟新的錯誤日誌。
在mysql 5.5 版本之後哦,伺服器將關閉此項功能,只能使用重新命名原來的錯誤日誌檔案,手動沖洗日誌建立一個新的日誌檔案,方法如下:

[root@db01 ~]# cd /usr/local/mysql/data/
[root@db01 data]# mv mysqld.err{,.old}
[root@db01 data]# mysqladmin -uroot -p123 flush-logs

二、二進位制日誌

二進位制日誌主要記錄MySQL資料庫的變化,二進位制日誌以一種有效的格式,並且是事務安全的方式包含更新日誌中可用的資訊。二進位制日誌包含了所有更新了資料或者已經潛在更新了資料。還包含關於每個更新資料庫的語句和執行時間,它不包含沒有修改任何資料的語句。使用二進位制日誌的主要目的是最大可能的恢復資料庫。

2.1 啟用二進位制日誌

預設情況下是關閉的!

[root@db01 ~]# vim /etc/my.cnf
[mysqld]
log-bin=/usr/local/mysql/data/binary_log    #指定二進位制日誌存放路徑及名稱
expire_logs_days=10            #儲存日誌的時間
max_binlog_size=100M           #單個日誌檔案的大小限制
[root@db01 ~]# systemctl restart mysqld
[root@db01 ~]# ll /usr/local/mysql/data/binary_log.*
-rw-r----- 1 mysql mysql 154 4月  15 11:48 /usr/local/mysql/data/binary_log.000001
-rw-r----- 1 mysql mysql  40 4月  15 11:48 /usr/local/mysql/data/binary_log.index
[root@db01 ~]# mysql -uroot -p123
mysql> show variables like 'log_%';
+----------------------------------------+----------------------------------------+
| Variable_name                          | Value                                  |
+----------------------------------------+----------------------------------------+
| log_bin                                | ON                                     |
| log_bin_basename                       | /usr/local/mysql/data/binary_log       |
| log_bin_index                          | /usr/local/mysql/data/binary_log.index |

2.2 檢視二進位制日誌

MySQL二進位制日誌儲存了所有的變更資訊,MySQL二進位制日誌經常使用。當MySQL建立二進位制日誌檔案時,首先建立一個以’filename’為名稱,以’.index’為字尾的檔案;再建立一個以’filename’為名稱,以’.000001’為字尾的檔案。當MySQL服務重啟一次,以’.000001’為字尾的檔案會增加一個,並且字尾名加1遞增。如果日誌長度超過max_binlog_size的上限,也會建立一個新的日誌。 show binary logs;可以檢視當前的二進位制日誌檔案個數及其檔名。

二進位制日誌並不能直接檢視,如果想要檢視日誌內容,可以通過mysqlbinlog命令檢視:

mysql> show binary logs;     #檢視當前的二進位制日誌檔案個數及其檔名
+-------------------+-----------+
| Log_name          | File_size |
+-------------------+-----------+
| binary_log.000001 |       154 |
+-------------------+-----------+
[root@db01 ~]# mysqlbinlog /usr/local/mysql/data/binary_log.000001
#檢視日誌內容

2.3 刪除二進位制日誌

MySQL的二進位制檔案可以配置自動刪除,同時MySQL提供了手動刪除二進位制檔案的方法:

  • RESET MASTER:刪除所有的二進位制日誌檔案;
  • PURGE MASTER LOGS:只刪除部分二進位制日誌檔案;
  • Reset master:刪除所有二進位制日誌 ;
  • Purge master logs to ‘二進位制名’ :刪除單個二進位制日誌之前的;
mysql> purge master logs to 'binary_log.000001';
#刪除..01之前的二進位制日誌檔案
mysql> purge master logs before '20180101';
#刪除2018-01-01之前的日誌檔案

三、事務日誌

事務日誌(InnoDB特有的日誌,因為只有Innodb支援事務)可以幫助提高事務的效率。使用事務日誌,儲存引擎在修改表的資料時只需要修改其記憶體拷貝,再把修改行為記錄到持久在硬碟上的事務日誌中,而不用每次都將修改的資料本身持久到磁碟。事務日誌採用追加的方式,因此寫日誌的操作是磁碟上一小塊區域內的順序I/O,而不像隨機I/O需要在磁碟的多個地方移動磁頭,所以採用事務日誌的方式相對來說要快得多。事務日誌持久以後,記憶體中被修改的資料在後臺可以慢慢的刷回到磁碟。目前大多數的儲存引擎都是這樣實現的。 如果資料的修改已經記錄到事務日誌並持久化,但資料本身還沒有寫回磁碟,此時系統崩潰,儲存引擎在重啟時能夠自動恢復這部分修改的資料。具有的恢復方式則視儲存引擎而定。

3.1 檢視事務日誌

mysql> show global variables like 'innodb_lo%';
+--------------------------------+----------+
| Variable_name                  | Value    |
+--------------------------------+----------+
| innodb_lock_wait_timeout       | 50       |
| innodb_locks_unsafe_for_binlog | OFF      |
| innodb_log_buffer_size         | 16777216 |
| innodb_log_checksums           | ON       |
| innodb_log_compressed_pages    | ON       |
| innodb_log_file_size           | 50331648 |   #日誌檔案大小
| innodb_log_files_in_group      | 2        |   #DB中設定幾組事務日誌,預設是2 
| innodb_log_group_home_dir      | ./       |   #定義innodb事務日誌組的位置,此位置設定預設為MySQL的datadir 
| innodb_log_write_ahead_size    | 8192     |
+--------------------------------+----------+

| innodb_flush_log_at_trx_commit | 1 #在事務提交時innodb是否同步日誌從緩衝區到檔案中,當這個值為1(預設值)之時,在每個事務提交時,日誌緩衝被寫到日誌檔案,對日誌檔案做到磁碟操作的重新整理,效能會很差造成大量的磁碟I/O但這種方式最安全;如果設為2,每次提交事務都會寫日誌,但並不會執行刷的操作。每秒定時會刷到日誌檔案。要注意的是,並不能保證100%每秒一定都會刷到磁碟,這要取決於程序的排程。每次事務提交的時候將資料寫入事務日誌,而這裡的寫入僅是呼叫了檔案系統的寫入操作,而檔案系統是有快取的,所以這個寫入並不能保證資料已經寫入到物理磁碟。設定為0,日誌緩衝每秒一次地被寫到日誌檔案,並且對日誌檔案做到磁碟操作的重新整理,但是在一個事務提交不做任何操作。

刷寫的概念:

刷寫其實是兩個操作,刷(flush)和寫(write),區分這兩個概念是很重要的。在大多數的作業系統中,把Innodb的log buffer(記憶體)寫入日誌(呼叫系統呼叫write),只是簡單的把資料移到作業系統快取中,作業系統快取同樣指的是記憶體。並沒有實際的持久化資料。

所以,通常設為0和2的時候,在崩潰或斷電的時候會丟失最後一秒的資料,因為這個時候資料只是存在於作業系統快取。之所以說“通常”,可能會有丟失不只1秒的資料的情況,比如說執行flush操作的時候阻塞了。

總結:設為1當然是最安全的,但效能頁是最差的(相對其他兩個引數而言,但不是不能接受)。如果對資料一致性和完整性要求不高,完全可以設為2,如果只最求效能,例如高併發寫的日誌伺服器,設為0來獲得更高效能。

每個事務日誌都是大小為50兆的檔案(不同版本的mysql有差異): 在mysql中預設以ib_logfile0,ib_logfile1名稱存在。

四、慢查詢日誌

顧名思義,慢查詢日誌中記錄的是執行時間較長的query,也就是我們常說的slow query。 慢查詢日誌採用的是簡單的文字格式,可以通過各種文字編輯器檢視其中的內容。其中記錄了語句執行的時刻,執行所消耗的時間,執行使用者,連線主機等相關資訊。 慢查詢日誌的作用: 慢查詢日誌是用來記錄執行時間超過指定時間的查詢語句。通過慢查詢日誌,可以查找出哪些查詢語句的執行效率很低,以便進行優化。一般建議開啟,它對伺服器效能的影響微乎其微,但是可以記錄mysql伺服器上執行了很長時間的查詢語句。可以幫助我們定位效能問題的。MySQL 還提供了專門用來分析滿查詢日誌的工具程式mysqldumpslow,用來幫助資料庫管理人員解決可能存在的效能問題。

4.1 檢視慢日誌的定義

mysql> show global variables like '%slow_query_log%';
#查詢慢查詢日誌是否開啟
+---------------------+-------------------------------------+
| Variable_name       | Value                               |
+---------------------+-------------------------------------+
| slow_query_log      | OFF                                 |
| slow_query_log_file | /usr/local/mysql/data/db01-slow.log |
+---------------------+-------------------------------------+
#OFF表示未開啟,下面表示檔案存放的路徑
mysql> show global variables like '%long%';
#檢視如何定義語句為慢查詢語句
+----------------------------------------------------------+-----------+
| Variable_name                                            | Value     |
+----------------------------------------------------------+-----------+
| long_query_time                                          | 10.000000 |
| performance_schema_events_stages_history_long_size       | 10000     |
| performance_schema_events_statements_history_long_size   | 10000     |
| performance_schema_events_transactions_history_long_size | 10000     |
| performance_schema_events_waits_history_long_size        | 10000     |
+----------------------------------------------------------+-----------+
#long_query_time的值就是慢查詢超時時間,預設為10s,只要執行耗時超過10s的語句就被定義為慢查詢語句

4.2 啟動和設定慢查詢日誌

① 啟動慢查詢日誌記錄

方法一

[root@db01 ~]#  vim /etc/my.cnf
#編輯主配置檔案,在mysqld欄位下寫入以下幾行
[mysqld]
slow_query_log=1       # 1表示開啟慢查詢
slow_query_log_file=/usr/local/mysql/data/mysql-slow.log   #指定慢查詢日誌位置
long_query_time=0.0001       #指定超時時間,也就是超過這個時間就會被記錄到慢查詢日誌
slow_launch_time=1     #如果建立執行緒花費了比這個值更長的時間,slow_launch_threads計數器將增加
[root@db01 ~]# systemctl restart mysqld     #重啟服務使配置生效
mysql> show global variables like '%slow_query_log%';
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_query_log      | ON                                   |
| slow_query_log_file | /usr/local/mysql/data/mysql-slow.log |
+---------------------+--------------------------------------+
#慢查詢日誌功能已經開啟
mysql> show global variables like '%long%';
+----------------------------------------------------------+----------+
| Variable_name                                            | Value    |
+----------------------------------------------------------+----------+
| long_query_time                                          | 0.000100 |
| performance_schema_events_stages_history_long_size       | 10000    |
| performance_schema_events_statements_history_long_size   | 10000    |
| performance_schema_events_transactions_history_long_size | 10000    |
| performance_schema_events_waits_history_long_size        | 10000    |
+----------------------------------------------------------+----------+
#修改的引數已經生效

方法二

mysql> set global slow_query_log=1;
mysql> set global long_query_time=0.0001;

global表示全域性生效,還有一個選項就是session,表示僅在當前會話生效,其區別是,session在退出當前會話後就會被重置,global則是在重啟MySQL服務後才會重置,而方法1中寫入配置檔案中的方式則是永久生效!

注意:如果主配置檔案中定義了long_query_time的值,並且MySQL命令列中使用set指令又定義了long_query_time的值,則配置檔案中定義的值優先生效。

② 檢視慢查詢日誌

若想要查詢到慢查詢日誌,必須保證兩點,首先是將慢查詢的超時時間設定的短一些,比如我在上面設定為了0.0001,只要查詢的時間超過了這個值,則被定義為慢查詢。(為了驗證效果,在生產環境中還是要結合實際情況)。第二呢,就是在開啟慢查詢後還需要執行幾條查詢語句,以便產生日誌記錄資訊(自己隨便查詢兩句吧)。

[root@db01 ~]# mysqldumpslow /usr/local/mysql/data/mysql-slow.log
#使用mysqldumpslow工具檢視慢查詢日誌

mysqldumpslow工具常用指令:

使用選項進行檢視:

[root@db01 ~]# mysqldumpslow -t 2 -a -s c /usr/local/mysql/data/mysql-slow.log
#以次數來排序,查詢前兩條,並且顯示語句的所有內容

五、資料檔案

在MySQL 中每一個數據庫都會在定義好(或者預設)的資料目錄下存在一個以資料庫名字命名的資料夾,用來存放該資料庫中各種表資料檔案。不同的MySQL 儲存引擎有各自不同的資料檔案。如MyISAM 用“.MYD”作為副檔名,Innodb 用“.ibd”,Archive 用“.arc”,CSV 用“.csv”,等等。

“.frm”檔案 與表相關的元資料(meta)資訊都存放在“.frm”檔案中,包括表結構的定義資訊等。不論是什麼儲存引擎(MySQL常用的兩個儲存引擎是MyISAM和InnoDB),每一個表都會有一個以表名命名的“.frm”檔案。所有的“.frm”檔案都存放在所屬資料庫的資料夾下面。

MyISAM資料庫表文件

.MYD檔案:表資料檔案;.MYI檔案:索引檔案

  • “.MYD”檔案 “.MYD”檔案是MyISAM儲存引擎專用,存放MyISAM 表的資料。每一個MyISAM 表都會有一個“.MYD”檔案與之對應,同樣存放於所屬資料庫的資料夾下,和“.frm”檔案在一起;
  • “.MYI”檔案 “.MYI”檔案也是專屬於MyISAM 儲存引擎的,主要存放MyISAM 表的索引相關資訊。對於MyISAM 儲存來說,可以被cache 的內容主要就是來源於“.MYI”檔案中。每一個MyISAM 表對應一個“.MYI”檔案,存放於位置和“.frm”以及“.MYD”一樣;

Innodb資料庫表文件

InnoDB採用表空間(tablespace)來管理資料,儲存表資料和索引。

  • .ibd檔案:單表表空間檔案,每個表使用一個表空間檔案(file per table),存放使用者資料庫表資料和索引;
  • InnoDB共享表空間(即InnoDB檔案集,ibfile set):ibdata1、ibdata2等,儲存InnoDB系統資訊和使用者資料庫表資料和索引,所有表共用;
  • “.ibd”檔案和ibdata 檔案 這兩種檔案都是存放Innodb 資料的檔案,之所以有兩種檔案來存放Innodb 的資料(包括索引),是因為Innodb 的資料儲存方式能夠通過配置來決定是使用共享表空間存放儲存資料,還是獨享表空間存放儲存資料。獨享表空間儲存方式使用“.ibd”檔案來存放資料,且每個表一個“.ibd”檔案,檔案存放在和MyISAM資料相同的位置;
  • 如果選用共享儲存表空間來存放資料,則會使用ibdata 檔案來存放,所有表共同使用一個(或者多個,可自行配置)ibdata 檔案。 ibdata 檔案可以通過innodb_data_home_dir 和innodb_data_file_path兩個引數共同配置組成, innodb_data_home_dir 配置資料存放的總目錄, 而innodb_data_file_path 配置每一個檔案的名稱。innodb_data_file_path 中可以一次配置多個ibdata 檔案。檔案可以是指定大小,也可以是自動擴充套件的,但是Innodb 限制了僅僅只有最後一個ibdata 檔案能夠配置成自動擴充套件型別。當我們需要新增新的ibdata 檔案的時候,只能新增在innodb_data_file_path配置的最後,而且必須重啟MySQL 才能完成ibdata 的新增工作。不過如果我們使用獨享表空間儲存方式的話,就不會有這樣的問題;

總結

共享表空間以及獨佔表空間都是針對資料的儲存方式而言的。

  • 共享表空間: 某一個數據庫的所有的表資料,索引檔案全部放在一個檔案中;
  • 獨佔表空間: 每一個表都將會生成以獨立的檔案方式來進行儲存,每一個表都有一個.frm表描述檔案,還有一個.ibd檔案。其中這個檔案包括了單獨一個表的資料內容以及索引內容;

共享表空間優缺點:

  • 優點:可以將表空間分成多個檔案存放到各個磁碟上。資料和檔案放在一起,方便管理;
  • 缺點:所有的資料和索引存放到一個檔案中,多個表及索引在表空間中混合儲存,這樣對於一個表做了大量操作後表空間將會有大量的空隙,特別是對於統計分析,日誌系統這類應用最不合適用共享表空間;

獨立表空間優缺點:

優點:

  • 每個表都有自己獨立的表空間;
  • 每個表的資料和索引都會存在自己的表空間中;
  • 可以實現單表在不同的資料庫中移動;
  • 空間可以回收:
    • a) Drop table操作自動回收表空間,如果對於統計分析或是日值表,刪除大量資料後可以通過:alter table TableName engine=innodb;回縮不用的空間;
    • b)對於使用獨立表空間的表,不管怎麼刪除,表空間的碎片不會太嚴重的影響效能,而且還有機會處理;

缺點:

  • 單表增加過大,如超過100G。相比較之下,使用獨立表空間的效率以及效能會更高一點;

5.1 檢視當前資料庫的表空間管理型別

mysql> show variables like '%innodb_file_per%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
#ON表示獨立表空間管理,OFF代表共享表空間管理
#檢視單表的表空間管理方式,需要檢視每個表是否有單獨的資料檔案

5.2 修改InnoDB共享表空間

[root@db01 ~]# vim /etc/my.cnf        #編輯主配置檔案,在mysqld欄位下寫入以下配置
innodb_file_per_table=0   #0為使用共享表空間,1為獨佔表空間
innodb_data_file_path=ibdata1:100M:autoextend    #設定一個可自動擴充套件大小,尺寸為100M的資料檔案
innodb_data_home_dir=/usr/local/mysql/data #定義共享表空間預設存放路徑
[root@db01 ~]# systemctl restart mysqld    #啟動報錯了
[root@db01 ~]# tail -20 /usr/local/mysql/data/mysqld.err
2020-04-15T06:49:39.410299Z 0 [ERROR] InnoDB: The Auto-extending innodb_system data file '/usr/local/mysql/data/ibdata1' is of a different size 768 pages (rounded down to MB) than specified in the .cnf file: initial 6400 pages, max 0 (relevant if non-zero) pages!
#查詢錯誤日誌,以上最關鍵的一行

注:不同版本的mysql報錯略有不同,注意看錯誤日誌的內容。大概意思就是設定的pages頁為6400,超過了它的最大值768,那麼算一下,設定的初始大小100M,pages大小就是6400,則表示1M=64pages,它的最大值是768,也就是說,我們設定初始大小最大可以是768/64=12M。

[root@db01 ~]# vim /etc/my.cnf
innodb_data_file_path=ibdata1:12M:autoextend
[root@db01 ~]# systemctl restart mysqld
#同樣,如果還是啟動失敗,則再次檢視錯誤日誌,是否pages頁大小設定的還是不合理

5.3 檢視修改後資料庫的表空間管理型別

mysql> show variables like '%innodb_file_per%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF   |
+-----------------------+-------+
#此時狀態為OFF,則表示使用的是共享表儲存空間,之後建立的表都會使用定義的共享表空間來儲存資料。