一、MySQL日志文件
mysql日志文件及功能:
日志文件 |
功能 |
錯誤日志 |
記錄啟動、停止、運行過程中mysqld時出現的問題 |
通用日志 |
記錄建立客戶端連接和執行的語句 |
二進制日志 |
記錄更改數據的所有語句,還用於復制 |
慢查詢日志 |
記錄執行時間超過long_query_time秒的所有查詢 |
默認情況下,mysql所有日志均存儲於mysql數據目錄下。通過刷新日志,可以時mysqld強制關閉和打開日志文件(或者在某些情況下切換到下一個日志)。
刷新日志方法:
1)flush logs
2)mysqladmin flush-logs
3)mysqladmin refresh
1、錯誤日志
1)作用:記錄mysqld啟動、停止以及mysql數據庫在運行過程中發生的各種嚴重錯誤信息。當數據庫發生任何故障導致無法重啟時,可以參考錯誤日志進行故障診斷。
2)位置:可以使用--log-error[=file_name]參數選項來指定mysqld保存錯誤日志文件的位置。如果沒有給定file_name文件位置,mysqld使用的錯誤日志名為host_name.err並默認保存在datadir指定的目錄下。
2、通用日志
1)作用:查詢日志記錄客戶端的所有語句(所有連接和語句都記錄到通用日志),而binlog不記錄select語句。
2)位置:查詢日志和慢查詢日志都可以保存在文件或表中,並使用參數--log-output[=value]來進行控制,value的值可以是table,file,none的一個或多個的組合,中間用逗號進行分割,分別表示日志保存在表,文件,不保存在表或文件中,這里的表指的是mysql庫總的general_log(慢查詢日志是slow_log)表。其中none的優先級最高,比如--log-output=table,file表示日志同時輸出到表和文件中,--log-output=table,none表示日志不保存在表中。如果不顯示使用此參數,則表示日志輸出到文件中。一般日志輸出到表中要占用更多的系統資源。
如果要啟用查詢日志,可以通過參數--general_log[={0|1}]和--general_log_file=file_name來進行控制。前者控制是否啟用查詢日志(--general_log設置為1或者不帶值都可以啟用查詢日志,設置為0表示關閉查詢日志,不指定此參數表示不啟動查詢日志),后者控制日志文件的路徑。也可以使用--log[=file_name]或-l [file_name]選項啟動它,如果沒有給出file_name,那么默認值就是host_name.log。運行時可以通過set global general_log on打開通用日志。
如果沒有指定--general_log_file=file_name值,且沒有顯示設置--log_output參數,那么日志默認寫入datadir目錄下的,默認文件名為host_name.log。這兩個參數都是global類型,可以在啟動時或系統運行時動態修改。如果想在session級別控制日志是否被記錄,則通過在session中設置參數sql_log_off為on或off來進行控制。
查詢通用日志位置:
mysql> show variables like 'gene%';
+------------------+--------------------------------------+
| Variable_name | Value |
+------------------+--------------------------------------+
| general_log | OFF |
| general_log_file | /usr/local/mysql/data/chavinking.log |
+------------------+--------------------------------------+
2 rows in set (0.00 sec)
3)日志內容的讀取:查詢日志為文本文檔格式,一般直接讀取就可。
4)一般情況下不建議開啟查詢日志功能,否則可能造成短時間內磁盤占用率猛增。
3、慢查詢日志
1)概述:當參數slow_query_log=1時,慢查詢日志記錄了所有執行時間超過參數long_query_time設置值並且掃描記錄數不小於min_examined_row_limit的所有sql語句的日志(獲得表鎖定的時間不能算作執行時間)。當沒有給出慢查詢日志名時,默認為主機名,后綴為-slow.log,當給出了文件名,但不是絕對路徑,慢查詢日志會記錄到mysql的數據目錄下。執行完語句並且釋放鎖后,即可記入慢查詢日志,記錄順序可以與執行順序不同。慢查詢日志可以查找執行時間長的語句,用於優化,它是MySQL數據中常用的性能優化工具。Long_query_time默認為10秒,最小為0,精度可以到微秒。
一般兩類語句不記錄到慢查詢日志中:管理語句和不使用索引進行查詢的語句。如果要監控這兩類SQL語句,可以分別通過參數--log-slow-admin-statements和log_queries_not_using_indexes進行控制。
2)文件位置和格式:慢查詢日志默認是關閉的,在mysql5.1.29前,當用--log-slow-queries[=file_name]選項啟動mysqld時,慢查詢日志開始被記錄。和前幾種日志一樣,如果沒有指定file_name的值,日志將寫入datadir路徑,默認文件名為host_name-slow.log。在mysql5.1.29后,--log-slow-queries參數廢棄,采用兩個新的參數進行替換:--slow_query_log[={0|1}]顯示指定慢查詢日志狀態,如果不指定值或指定值為1都會打開慢查詢;使用slow_query_log_file[=file_name]來指定慢查詢日志路徑,另外還可以指定--log-output參數指定日志的輸出格式,默認輸出到文件。需要注意的是如果選擇輸出到表,則表中的記錄的慢查詢時間只能精確到秒,而日志文件中可以精確到微秒。
3)日志文件的讀取:慢查詢日志文件是存文本方式存儲,可以直接讀取。也可以通過mysqldumpslow工具(../bin/mysqldumpslow faspdev-slow.log)對慢查詢日志進行匯總處理。慢查詢日志通常用來定位mysql服務中sql問題,默認建議打開慢查詢日志,並定期查看分析。
4)慢查詢日志在mysql性能優化中的作用詳解:
4.1)慢查詢日志格式:
mysql慢查詢標准:
query_time:查詢耗時
rows_examined:檢查多少條記錄
rows_sent:返回多少行記錄
mysql使用以上幾點大致衡量sql成本。
其他信息包括如下:
time:執行sql開始時間
lock time:等待table lock的時間,注意innodb行鎖等待不會反應在這里。
user@host:執行查詢的用戶和客戶端ip
以下是一個慢查詢例子:
# Time: 170122 13:53:17 # User@Host: root[root] @ localhost [] Id: 1 # Query_time: 9.839503 Lock_time: 0.000159 Rows_sent: 0 Rows_examined: 524288 SET timestamp=1485064397; insert into column_charset select * from column_charset; |
一般執行時間最長的sql是需要優化的,如果檢查了大量數據而只返回少量數據,則意味着質量不佳。需要注意的是慢查詢日志里的慢查詢不一定就是不良sql,還可能受其他查詢影響,或者受到系統資源限制導致的。
4.2)如何識別需要關注的sql:
確認已經開啟了慢查詢日志,並且設置了合理的閾值。以下命令可以查看是否啟用慢查詢日志以及慢查詢日志路徑:
mysql> show variables like '%slow_query_log%';
+---------------------+------------------------------------------- ------------------------+
| Variable_name | Value |
+---------------------+--------------------------------------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /usr/local/mysql5631/data/faspdev-slow.log |
+---------------------+-------------------------------------------------------------------+
以下命令可以查看全局變量long_query_time參數的值,所有超過該值得sql都將記錄到慢查詢日志中:
mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 1.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
在mysql參數文件中開啟慢查詢日志設置如下:
[mysqld]
slow_query_log=1
slow_query_log_file=/usr/local/mysql/data/log/slowquery.log
long_query_time=0.5
mysql 5.0慢查詢參數是不一樣的,且需要重啟后才可以生效,相關參數為log_slow_queries和slow_launch_time。
參數log-queries-not-using-indexes用於指定如果沒有使用到索引或雖然使用了索引但仍然遍歷了所有記錄,就將其記錄下來,默認此參數是關閉的。
4.3)使用工具分析慢查詢日志
如果慢查詢日志內容比較多,對於分析是比較麻煩的,一般有以下兩種辦法可以參考:
u 調整閾值
u 使用命令、腳本、工具進行分析,如mysqldumpslow、pt-query-digest等。
A. 使用操作系統命令進行分析:
可以使用shell命令進行統計分析,如grep、awk、wc,但是這些工具不容易實現高級功能。
awk '/^#Time:/{print $3,$4,c;c=0}/^#User/{c++}' mysql-slow.log > /mnt/slowquery.log
B. 使用mysqldumpslow工具進行分析:
mysqldumpslow工具是官方自帶的,此工具可以獲得日志中的查詢摘要。以下是mysqldumpslow工具使用幫助:
$mysqldumpslow --help Usage: mysqldumpslow [ OPTS... ] [ LOGS... ] Parse and summarize the MySQL slow query log. Options are --verbose verbose --debug debug --help write this text to standard output -v verbose -d debug -s ORDER what to sort by (t, at, l, al, r, ar etc), 'at' is default -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 |
查詢時間最長的10個sql:
mysqldumpslow -t 10 mysql-slow.log
查詢訪問次數最多的10個sql命令:
mysqldumpslow -s c -t 10 mysql-slow.log
查詢訪問記錄最多的10條sql命令:
mysqldumpslow -s r -t 10 mysql-slow.log
4.4)以下是mysql運行狀態下設置慢查詢日志的例子
mysql> show variables like 'long_query_time'; +-----------------+-----------+ | Variable_name | Value | +-----------------+-----------+ | long_query_time | 10.000000 | +-----------------+-----------+ 1 row in set (0.00 sec) mysql> set long_query_time=2; Query OK, 0 rows affected (0.00 sec) |
mysql> show variables like '%slow_query_log%'; +---------------------+--------------------------------------------+ | Variable_name | Value | +---------------------+--------------------------------------------+ | slow_query_log | OFF | | slow_query_log_file | /usr/local/mysql5631/data/faspdev-slow.log | +---------------------+--------------------------------------------+ 2 rows in set (0.00 sec) mysql> set global slow_query_log=1; Query OK, 0 rows affected (0.00 sec) |
4、binlog日志文件
1)作用:Binlog記錄了數據庫所有的ddl語句和dml語句,但不包括select語句內容,語句以事件的形式保存,描述了數據的變更順序,binlog還包括了每個更新語句的執行時間信息,binlog主要作用是用於恢復數據,因此binlog對於災難恢復和備份恢復來說至關重要。相當於oracle數據庫中的archivelog文件。
binlog還用於實現mysql主從復制。
二進制日志文件記錄了數據庫的變更過程,對於數據庫的安全性和完整性起着至關重要的作用。
2)位置和格式:當用--log-bin[=file_name]選項啟動時,mysqld開始將數據庫變更情況寫入日志文件。如果沒有給出file_name值,默認名為主機名-bin。如果給出了文件名,但不包含路徑,則文件默認被寫入datadir參數指定路徑。
mysqld將在每個binlog日志名后添加一個數字擴展名,每次要啟動服務器或刷新日志時,該數字將會增加,如果當前日志大小達到了max-binlog-size參數設置的值,那么mysqld會自動創建新的二進制日志。
mysqld還將創建一個binlog索引文件,其中包含了所有binlog文件的文件名,默認該索引文件與binlog文件名相同,擴展名為.index。當mysqld運行時,不可以手工編輯該索引文件,這樣可能導致mysqld異常。當rm刪除binlog后,你也許不得不手工編輯索引文件。
3)binlog日志格式
mysql有兩種記錄命令方式,一種是語句級(binlog_format=statement),一種是行級(binlog_format=row),建議命令格式設置為混合模式(binlog_format=mixed),這在大部分模式下試用,它在一般情況下試用語句級記錄,但是在一些特殊情況下試用行級記錄,這增加了復制的健壯性。
Mysq5.5中,二進制日志格式分為3種:statement,row和mixed,可以在啟動數據庫時通過參數--binlog_format進行設置,這3種格式區別如下:
3.1)statement:
Mysql5.1之前的版本都采用這種方式,binlog日志中記錄的都是語句(基於語句級的日志里包含了原始執行的sql語句,還有其他信息,如執行語句的線程id,語句執行的時間戳,執行所消耗時長),每一條對數據庫造成修改的語句都會記錄在日志中,通過mysqlbinlog工具,可以清晰的看到每條語句的文本。主從復制時,從庫的日志解析為原文本在從庫中執行。優點是日志量小,清晰易懂,對io壓力小,缺點是某些情況下slave的日志復制會出差。
3.2)row:
Mysql5.1.11之后出現的。它將每一行變更記錄到日志中,而不是記錄sql語句(記錄行的更改信息而不是語句)。優點是記錄每一行數據變化的細節,不會出現slave模式下某些情況無法復制的情況。缺點是日志量大,對io影響較大。通過mysqlbinlog默認看到的都是經過base-64編碼的信息,mysqlbinlog加參數-verbose(或-v)將會生成帶注釋的語句,如果連續兩次使用這個參數(如-v -v),則生成字段類型、長度、是否為null等屬性信息。
一般而言,row模式更為健壯,而statement級別如果應用了mysql的一些額外特性,比如存儲過程、觸發器,則可能導致復制異常,所以,如果使用語句級記錄,那么需要保持mysql數據庫應用的簡單性,即只用核心功能即可。
3.3)mixed:
這是目前mysql的默認binlog日志格式,即混合了statement和row兩種日志。默認情況下采用statement,但是在一些特殊情況下采用row方式記錄日志。此種模式利用statement和row的優點,而盡量避開他們的缺點。
注意:可以在global和session級別對binlog日志的格式進行修改。
4)日志文件的讀取
由於binlog以二進制方式存儲,不能直接讀取,因此需要使用mysqlbinlog工具進行日志分析,語法:mysqlbinlog log-file。
例:
4.1)以binlog方式啟動數據庫:
[root@faspdev bin]# ./mysqld_safe --user=mysql --log-bin=binlog-test
4.2)執行dml語句:
mysql> delete from t1;
Query OK, 2 rows affected (0.02 sec)
4.3)mysqlbinlog查看binlog內容:
[root@faspdev data]# ../bin/mysqlbinlog binlog-test.000001 /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #161111 17:45:52 server id 1 end_log_pos 120 CRC32 0x5bfb8e4f Start: binlog v 4, server v 5.6.31-log created 161111 17:45:52 at startup # Warning: this binlog is either in use or was not closed properly. ROLLBACK/*!*/; BINLOG ' UJMlWA8BAAAAdAAAAHgAAAABAAQANS42LjMxLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAABQkyVYEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAU+O +1s= '/*!*/; # at 120 #161111 17:47:29 server id 1 end_log_pos 199 CRC32 0x3f0abe26 Query thread_id=1 exec_time=0 error_code=0 SET TIMESTAMP=1478857649/*!*/; SET @@session.pseudo_thread_id=1/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1075838976/*!*/; 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/*!*/; BEGIN /*!*/; # at 199 #161111 17:47:29 server id 1 end_log_pos 287 CRC32 0x78e57a7e Query thread_id=1 exec_time=0 error_code=0 use `test`/*!*/; SET TIMESTAMP=1478857649/*!*/; delete from t1 /*!*/; # at 287 #161111 17:47:29 server id 1 end_log_pos 318 CRC32 0x0b2d7e98 Xid = 9 COMMIT/*!*/; DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; |
如果日志格式是row,mysqlbinlog解析的文件是無法讀懂的字符,可以加-v或-v -v進行查看。 |
5)默認情況下,並不是每次寫入時都將binlog與磁盤同步,因此操作系統或機器發生故障,那么binlog中最后的語句有可能會丟失。要防止這種情況發生,可以設置sync_binlog全局變量為n(1為最安全的值,同時也是最慢的),使binlog每n此寫入就與磁盤做同步。
6)日志文件的刪除
查看binlog方法:
mysql> show binary logs;
6.1)方法1:reset master刪除所有的binlog日志文件,刪除后的日志文件從1開始編號。
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
6.2)方法2:使用purge binary logs命令刪除部分binlog文件:
mysql> purge binary logs to 'mysql-bin.000001';
Query OK, 0 rows affected (0.03 sec)
6.3)方法3:purge master logs to ‘mysql-bin.******’命令,該命令刪除‘******’編號之前的所有日志文件。
6.4)方法4:purge master logs before ‘yyyy-mm-dd hh24:mi:ss’命令,該命令刪除‘yyyy-mm-dd hh24:mi:ss’日期之前的所有日志。
6.5)設置參數--expire_logs_days=#,此參數含義是設置日志過期天數, 過了指定天數后的日志將會被自動刪除,這樣有利於減少DBA管理日志的工作量。
7)mysqlbinlog解析:
u # at 199
u #161111 17:47:29 server id 1 end_log_pos 287
u # Query thread_id=1 exec_time=0 error_code=0
8)binlog管理相關參數
8.1)--binlog-do-db=db_name:該參數告訴主服務器,如果當前的數據庫是db_name,應該將其記錄到binlog中,其他沒有被指定的數據庫將被忽略,可多次使用,對多個數據庫進行定義。
8.2)--binlog-ignore-db=db_name:改參數告訴主服務器,如果當前數據庫為db_name,則不記錄binlog,其他沒有指定的數據庫變化將記錄binlog中,可多次使用,對多個數據庫進行定義。
8.3)--innodb-sage-binlog:該參數經常和--sync-binlog=N(沒寫N次日志同步磁盤)一起配合使用,使得事務在日志中的記錄更加安全。
8.4)Set sql_log_bin=0:具有super權限的客戶端可以通過此語句禁止將自己的語句記錄二進制文件,這個選項在某些環境下是有用的,比如主主切換,或者mysql版本升級,但是使用一定倍加小心,免得造成slave環境下的數據不一致。
5、日志文件維護
很多生產環境,日志文件可以占用大量的磁盤空間,因此,需要對日志文件進行定期清理操作,mysql服務器當然也不例外。
l 對於錯誤日志文件,一般不會太大,因此生產上注意一下就可以了。
l 通用日志一般生產不開啟,因此也不存在清理一說。
l 慢查詢日志在慢查詢很多的情況下可能變得很大,可以手工清理或編寫腳本管理。
l binlog日志文件可以設置合適的過期策略,如expire-logs-days=10,表示設置binlog過期時間為10天。expires-logs-days設置會在運行flush logs命令后觸發刪除過期日志,注意,不能使用rm刪除binlog日志文件,這可能導致你執行日志清理命令失敗。mysql 5.6可以設置保留binlog日志文件大小,避免磁盤對填滿。
二、innodb數據文件和日志文件
1、以下簡單介紹mysql數據目錄下的文件:
1)db.opt
數據庫結構定義和設置
2)*.frm
數據表的結構定義
3)*.MYD
Myisam引擎表數據
4)*.MYI
Myisam引擎索引數據
5)ibdata*
Innodb表空間數據文件
如果將innodb_file_per_table設置為1,那么innodb數據表可以各自存儲為一個文件,這種模式成為獨立表空間。如果將innodb_file_per_table設置為0,那么innodb數據則可以統一存儲在一個共享表空間里。
6)ib_logfile*
Innodb重做日志文件
7)*.idb
Innodb數據和索引。
8)*.trg
觸發器
2、innodb數據文件和日志文件
如果沒有再參數文件中指定innodb相關參數,那么mysql將會在data目錄下創建一個大小為10m的ibdata1文件和大小5m的兩個ib_logfile*文件。這種設置對於生產而言太小,一般建議設置logfile為256m,數據文件初始大小1g~5g,並且設置自動增長。
參數配置樣例:
Innodb_data_file_path=ibdata1:1000m:autiextend
Innodb_log_file_size=256m
Innodb_data_file_path的值可以設置為1個或多個列表。如果要命名一個以上的數據文件,請用“;”分隔它們。其語法格式為:Innodb_data_file_path=datafile01:size[;datafile02:size;...]。
例如:Innodb_data_file_path=datafile01:2000m;datafile02:2000m;datafile03:2000m:autoextend
其中autoextend及其后屬相只能用於Innodb_data_file_path列表中最后一個數據文件,針對於最后一個數據文件,如果innodb共享表空間耗盡后,就會擴展最后一個數據文件,默認擴展大小為8m。
1)innodb獨立表空間和共享表空間
共享表空間使用簡單,方便維護,但是也存在缺點,使用貢獻表空間明顯的缺點是不能快速回收刪除大表的空間,io操作可能會消耗更多的資源等待。而獨立表空間是大部分DBA推薦使用的方式,它恰好在這一點彌補了共享表空間不足。Innodb下使用獨立表空間,每個表都有它自己的表空間。
開啟獨立表空間方式:
在my.cnf文件中添加如下參數,重啟mysql實例即可生效:
[mysqld]
innodb_file_per_table
重啟實例后,innodb將會把新創建的表存儲到數據目錄下的文件tb1_name.ibd中,這類似域myisam存儲引擎所做的事,但是myisam把表分成數據文件tb1_name.MYD和索引文件tb1_name.MYI。對於innodb,數據和索引會放在一起,都存放到.ibd文件中,不過tb1_name.frm文件照舊會被創建。
在my.cnf文件中刪除了innodb_file_per_table行,重啟實例后,innodb新創建的表會存儲在共享表空間里,就是說innodb_file_per_table這個參數僅影響表的創建位置。innodb使用獨立表空間,也仍然有一部分數據在共享表空間里。
相對於myisam引擎管理的表,我們不能隨意移動.ibd文件,這是因為表定義是被存儲在innodb共享表空間里的,而innodb必須保持事務id和事務日志順序號的一致性。
2)innodb增加數據文件
手動增加一個innodb數據文件時需要重啟實例。為innodb存儲引擎管理表添加數據文件需要修改my.cnf參數文件,把innodb_data_file_path參數指定添加的數據文件及其初始大小和相關參數。注意當你添加一個數據文件到innodb_data_file_path時,需要確定它不存在,當你重啟實例時,innodb會自動創建這個數據文件。添加innodb數據文件需要首先計算當前innodb_data_file_path中最后一個數據文件大小,然后估計一個近似值給它,再添加新的數據文件。Innodb數據文件只有最后一個可以設置為自動擴展。
3)改變innodb重做日志大小
不要試圖通過直接更改配置文件來設置innodb事務日志大小,這會導致不能啟動數據庫。如果想要改變innodb事務日志的數量和大小,必須正常關閉mysql實例,然后復制舊日志文件到一個安全的地方做備份,然后從日志文件目錄刪除所有的舊日志文件,之后更改my.cnf參數文件改變日志文件配置,並再次啟動mysql實例。Mysqld在啟動時會發現沒有重做日志文件,然后告訴你它正在創建一個新的日志文件。
更改innodb事務日志步驟:
l 干凈關閉mysql實例
l 使用mv命令轉移innodb重做日志文件。
l 修改my.cnf配置文件,更改innodb_log_file_size
l 啟動mysql實例
注意,舊版本mysql服務器重做日志總大小不能超過4g,在mysql5.6以后,限制擴展到521g。
4)innodb的undo區域
Undo區域也稱為undo空間或undo表空間,是innodb設計的一塊特殊存儲區域,它保存了被活動事務更改的數據的副本(鏡像),如果一個事務需要查看原來的數據(滿足一致性讀),那么可以從undo區域中獲得未被更改的數據。默認情況下,undo區域也是在innodb共享表空間內。Mysql5.6以后提供了選項,可以把undo表空間獨立到表空間,這樣就可以進行熱點塊的io優化,提升性能。
如果undo表空間暴漲,出現這種情況可能是因為負載比較大,或者存在長時間未提交的事務(長事務)。
對於寫操作比較頻繁的應用,innodb清理線程的速度可能會跟不上,從而導致undo表空間越來越大,可以通過設置innodb_max_purge_lag參數來避免undo空間過度增大。Innodb事務系統維持一個事務列表,該列表記錄被update或delete操作表示為刪除的索引記錄。這個列表的長度為purge_lag。當purge_lag超過了nnodb_max_purge_lag時,每個dml語句都被延遲一定時間。
Undo空間里保存了數據的前鏡像,這是滿足一致性讀的根本原因,同時也是災難恢復的重要角色(即回滾)。
3、臨時文件
Mysql臨時文件作用類似但不等同於oracle臨時表空間。Mysql使用環境變量TMPDIR的值作為保存臨時文件的目錄。如果未設置,則默認使用系統的默認值,一般為/tmp,/var/tmp,/usr/tmp。可以使用--tmpdir參數在啟動時指定mysql臨時目錄,或者在my.cnf文件中指定tmpdir參數進行分配。
如果mysql服務器正在作為復制服務器使用,那么不能將mysql臨時路徑指向基於內存的文件系統目錄或者主機重啟會清空的目錄,否則可能造成復制失敗。Mysql隱含創建所有的臨時文件。進行排序操作時,mysql會使用一個或多個臨時文件。一定要保證臨時目錄空間夠用。一些普通的數據庫操作都有可能創建臨時文件用於維護數據庫內的數據結構,alter table會在原表所在目錄下創建臨時表。
4、mysql套接字文件
服務器用來與本地客戶端進行通信的linux套接字文件(也稱為socket文件)默認位置是/tmp/mysql.sock。Scoket文件不建議放置在/tmp目錄下,可以將其單獨指定存儲位置,我們可以通過my.cnf配置文件指定mysql socket文件存儲路徑,下面是my.cnf中定義socket儲存路徑:
[mysqld]
Socket=/opt/mysql/mysql.socket
[client]
Socket=/opt/mysql/mysql.socket
Mysql服務器一定要保留root的除了socket外的其他登錄方式,比如通過127.0.0.1的root登錄賬號,以防止socket文件被刪除導致無法登錄mysql數據庫的窘境。
三、MySQL災難恢復過程
1、預寫日志和undo表空間
mysql靠預寫日志(innodb事務日志)來保證數據持久性,也就是說數據文件不會先被寫入,而是先寫日志文件。innodb臟數據存在於innodb_buffer_pool里,它會按照一定的機制批量寫入磁盤,這樣可以提高吞吐率。
mysql宕機后的實例恢復過程:首先mysql找到事務日志中的某個點,從該點開始重做redo中的事務,在應用了所有redo日志后,根據undo區域確定哪些事務需要回滾,然后回滾哪些沒有提交的事務,簡單理解,mysql災難恢復過程就是根據redo重做日志,然后根據undo回退事務。
innodb事務日志很大程度上決定了數據的安全性,日志的持久性決定了災難恢復后丟失多少數據!mysql可以通過參數控制commit時寫入事務日志的頻率,通常有以下3種情況:
1)innodb_flush_log_at_trx_commit=1
每次commit時都寫入磁盤,這樣理論上發生故障時我們只丟失一個事務。
2)innodb_flush_log_at_trx_commit=2
每次commit,只寫日志緩存到操作系統緩沖,但不刷新磁盤,innodb每秒刷新磁盤一次,所以故障丟失的是最近1秒的數據。生產環境建議這樣設置。
3)innodb_flush_log_at_trx_commit=0
每秒把日志緩沖的內容寫入到日志文件,並且刷新到磁盤,但commit時什么也不做。
2、雙寫緩沖
數據文件的寫操作,可能會將塊寫壞,mysql設計了一個數據存儲區域雙寫緩沖,innodb使用雙寫緩沖來確保數據的安全,避免塊損壞。雙寫緩沖是innodb表空間的一個特殊區域,主要用於寫入頁的備份,並且是順序寫入的。當innodb刷新數據時,首先寫入雙寫緩沖,然后寫入數據文件。這樣既可確保所有寫操作的原子性和持久性。
崩潰重啟后,innodb會檢查每個塊的校驗和,判斷塊是否損壞,如果寫入雙寫緩沖的是壞塊,那么顯然沒有寫入實際數據文件,那么用數據文件的塊恢復雙寫緩沖;如果寫入了雙寫緩沖,但是數據文件中的是壞塊,那么使用雙寫緩沖中的塊恢復實際數據文件中的塊。這樣的機制提供了雙層的安全保障,但是缺點是增加了io。
對於讀取操作,innodb通過頁校驗和來保證數據的存取,每頁在內存中都先算好一個校驗值,放在文件頭部,寫入的時候先寫校驗值,讀的時候也會校驗一下校驗值。
四、mysql參數文件及參數修改方法
MySQL數據庫初始化參數由參數文件來設置,如果沒有設置參數文件,mysql就按照系統中參數的默認值來啟動。在windows和linux上,參數文件可以被放在多個位置,數據庫啟動時按照不同的順序來搜索,如果多個位置都有參數文件,則搜索順序靠后的參數文件中的參數將覆蓋前的參數。
表:linux下mysql參數文件讀取順序:
參數文件名 |
目的 |
/etc/my.cnf |
全局選項 |
$MYSQL_HOME/my.cnf |
服務器相關選項 |
Default-extra-file |
用--Default-extra-file=path選項指定的文件,如果該文件存在的話 |
~/.my.cnf |
用戶相關選項 |
Mysql安裝上述順序尋找參數文件,如果多個文件同時存在,那么文件中指定的后讀取的選項要優先於先讀取的選項,所以數據目錄或安裝目錄下的配置文件都有可能生效,所以理論上在數據目錄或安裝目錄下放置一個my.cnf文件即可。Mysql啟動時可以指定--datadir用於指定數據路徑,但是此選項對於查詢參數文件無效,因為在讀取--datadir之前mysql服務器就已經讀取了配置文件了。多次指定一個選項,后出現的將覆蓋先出現的值,因此命令行中通過set修改的選項優先級最高。
通過如下命令可以列出mysqld讀取參數文件的優先順序:該命令不能在生產環境隨意運行
$mysqld --verbose --help |grep my.cnf
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf
Mysql參數可以在3個級別進行更改:
1)session級別:set
2)全局級別:set global
3)永久級別:my.cnf
附:一份生產可用的mysql配置文件(my.cnf)示例(測試庫mysql 5.6.24): |
[client] #客戶端選項設置 port = 3306 socket = /opt/mysql-5.6.24/data/mysql.socket #設置客戶端和連接字符集 default_character_set = utf8 [mysqld] #服務器端選項設置 # innodb設置 default_storage_engine = InnoDB innodb_strict_mode = 1 innodb_buffer_pool_size = 256M #mysql數據庫服務器,該值可設為物理內存的50%-80%之間 innodb_stats_on_metadata = 0 innodb_file_format = Barracuda innodb_data_file_path=ibdata1:10m:autoextend innodb_flush_method = O_DIRECT innodb_log_files_in_group = 2 innodb_log_file_size = 16M innodb_log_buffer_size = 8M innodb_file_per_table = 1 innodb_max_dirty_pages_pct = 60 innodb_io_capacity = 200 innodb_flush_log_at_trx_commit = 2 # 基本設置 basedir = /opt/mysql-5.6.24 datadir = /opt/mysql-5.6.24/data port = 3306 server_id = 19900315 tmpdir = /opt/mysql-5.6.24/tmp socket = /opt/mysql-5.6.24/tmp/mysql.socket Pid-file = /opt/mysql-5.6.24/data/mysql.pid skip-name-resolve = 1 skip-external-locking = 1 max_connect_errors = 500 max_connections = 1000 relay-log = mysql-relay-bin log-slave-updates = 1 skip_slave_start = 1 read_only = 0 key_buffer_size = 8M tmp_table_size = 8M max_heap_table_size = 8M query_cache_type = 0 query_cache_size = 0 thread_cache_size = 1024 open_files_limit = 65535 table_open_cache = 1024 max_allowed_packet = 16M gtid-mode = ON enforce-gtid-consistency = 1 lower_case_table_names=1 log-bin-trust-function-creators plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" replicate-ignore-table = mysql.ibbackup_binlog_marker slave-skip-errors = ddl_exist_errors relay-log-info-repository = TABLE relay_log_recovery = 1 master_info_repository = TABLE # 服務器字符集設置 character_set_server = utf8 # error log設置 log_error = /opt/mysql-5.6.24/data/mysql.err # slow log設置 slow_query_log = 1 slow_query_log_file = /opt/mysql-5.6.24/data/mysql-slow.log long_query_time = 0.5 # binlog設置 binlog_format = mixed log-bin = /opt/mysql-5.6.24/logs/mysql-bin sync_binlog = 2 max_binlog_size = 16M expire_logs_days = 10 #others設置 join_buffer_size = 128M sort_buffer_size = 2M read_rnd_buffer_size = 2M sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES |