MySQL中InnoDB存儲引擎底層原理與MySQL日志機制深入解析

MySQL的內部組件結構如下:
在這里插入圖片描述
大體來說,MySQL 可以分為 Server 層和存儲引擎層兩部分。

Server層

主要包括連接器、查詢緩存、分析器、優化器、執行器等,涵蓋 MySQL 的大多數核心服務功能,以及所有的內置函數(如日期、時間、數學和加密函數等),所有跨存儲引擎的功能都在這一層實現,比如存儲過程、觸發器、視圖等。

存儲引擎層

存儲引擎層負責數據的存儲和提取。其架構模式是插件式的,支持 InnoDB、MyISAM、Memory 等多個存儲引擎。現在最常用的存儲引擎是 InnoDB,它從 MySQL 5.5.5 版本開始成為了默認存儲引擎。也就是說如果在create table時不指定表的存儲引擎類型,默認會給你設置存儲引擎為InnoDB。

連接器

由于MySQL是開源的,它有非常多種類的客戶端:navicat,mysql front,jdbc,SQLyog等非常豐富的客戶端,包括各種編程語言實現的客戶端連接程序,這些客戶端要向mysql發起通信都必須先跟Server端建立通信連接,而建立連接的工作就是有連接器完成的。
第一步,先連接到這個數據庫上,這時候接待你的就是連接器。連接器負責跟客戶端建立連接、獲取權限、維持和管理連接。連接命令一般是這么寫的:

[root@192 ~]# mysql -h host[數據庫地址] -u root[用戶] -p root[密碼] -P 3306

連接命令中的 mysql 是客戶端工具,用來跟服務端建立連接。在完成經典的 TCP 握手后,連接器就要開始認證你的身份,這個時候用的就是你輸入的用戶名和密碼。

  1. 如果用戶名或密碼不對,會收到一個"Access denied for user"的錯誤,然后客戶端程序結束執行。
  2. 如果用戶名密碼認證通過,連接器會到權限表里面查出擁有的權限。之后,這個連接里面的權限判斷邏輯,都將依賴于此時讀到的權限。

這就意味著,一個用戶成功建立連接后,即使用管理員賬號對這個用戶的權限做了修改,也不會影響已經存在連接的權限。修改完成后,只有再新建的連接才會使用新的權限設置。

查詢緩存

連接建立完成后,你就可以執行 select 語句了。執行邏輯就會來到第二步:查詢緩存。
MySQL 拿到一個查詢請求后,會先到查詢緩存看看,之前是不是執行過這條語句。之前執行過的語句及其結果可能會以 key-value 對的形式,被直接緩存在內存中。key 是查詢的語句,value 是查詢的結果。如果你的查詢能夠直接在這個緩存中找到 key,那么這個 value 就會被直接返回給客戶端。
如果語句不在查詢緩存中,就會繼續后面的執行階段。執行完成后,執行結果會被存入查詢緩存中。你可以看到,如果查詢命中緩存,MySQL 不需要執行后面的復雜操作,就可以直接返回結果,這個效率會很高。

大多數情況查詢緩存就是個雞肋,為什么呢?
因為查詢緩存往往弊大于利。查詢緩存的失效非常頻繁,只要有對一個表的更新,這個表上所有的查詢緩存都會被清空。因此很可能你費勁地把結果存起來,還沒使用呢,就被一個更新全清空了。對于更新壓力大的數據庫來說,查詢緩存的命中率會非常低。
一般建議在靜態表里使用查詢緩存,什么叫靜態表呢?就是一般極少更新的表。比如,一個系統配置表、字典表,那這張表上的查詢才適合使用查詢緩存。好在 MySQL 也提供了這種“按需使用”的方式,可以將my.cnf參數 query_cache_type 設置成 DEMAND。

my.cnf
#query_cache_type有3個值 0代表關閉查詢緩存OFF,1代表開啟ON,2(DEMAND)代表當sql語句中有SQL_CACHE關鍵詞時才緩存
query_cache_type=2

這樣對于默認的 SQL 語句都不使用查詢緩存。而對于確定要使用查詢緩存的語句,可以用 SQL_CACHE 顯式指定,像下面這個語句一樣:

mysql> select SQL_CACHE * from test where ID=5

查看當前MySQL實例是否開啟緩存機制

mysql> show global variables like "%query_cache_type%";

MySQL 8.0已經移除了查詢緩存功能

分析器

如果沒有命中查詢緩存,就要開始真正執行語句了。首先,MySQL 需要知道你要做什么,因此需要對 SQL 語句做解析。
分析器先會做“詞法分析”。你輸入的是由多個字符串和空格組成的一條 SQL 語句,MySQL 需要識別出里面的字符串分別是什么,代表什么。
MySQL 從你輸入的"select"這個關鍵字識別出來,這是一個查詢語句。它也要把字符串“T”識別成“表名 T”,把字符串“ID”識別成“列 ID”。
做完了這些識別以后,就要做“語法分析”。根據詞法分析的結果,語法分析器會根據語法規則,判斷你輸入的這個 SQL 語句是否滿足 MySQL 語法。
如果你的語句不對,就會收到“You have an error in your SQL syntax”的錯誤提醒,比如下面這個語句 from 寫成了 “rom”。

mysql> select * fro test where id=1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'fro test where id=1' at line 1

下圖是分析器對SQL的分析過程步驟
在這里插入圖片描述
SQL語句經過分析器分析之后,會生成一個這樣的語法樹
在這里插入圖片描述

優化器

經過了分析器,MySQL 就知道你要做什么了。在開始執行之前,還要先經過優化器的處理。
優化器是在表里面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的連接順序;以及一些MySQL自己內部的優化機制。

執行器

開始執行的時候,要先判斷一下你對這個表 T 有沒有執行查詢的權限,如果沒有,就會返回沒有權限的錯誤,如下所示 (在工程實現上,如果命中查詢緩存,會在查詢緩存返回結果的時候,做權限驗證)。

mysql> select * from test where id=10;

如果有權限,就打開表繼續執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口。

Innodb底層原理與Mysql日志機制

在這里插入圖片描述

redo log重做日志關鍵參數

innodb_log_buffer_size:設置redo log buffer大小參數,默認16M ,最大值是4096M,最小值為1M。

show variables like '%innodb_log_buffer_size%';

innodb_log_group_home_dir:設置redo log文件存儲位置參數,默認值為"./",即innodb數據文件存儲位置,其中的 ib_logfile0 和 ib_logfile1 即為redo log文件。

show variables like '%innodb_log_group_home_dir%';

在這里插入圖片描述
innodb_log_files_in_group:設置redo log文件的個數,命名方式如: ib_logfile0, iblogfile1… iblogfileN。默認2個,最大100個。

show variables like '%innodb_log_files_in_group%';

innodb_log_file_size:設置單個redo log文件大小,默認值為48M。最大值為512G,注意最大值指的是整個 redo log系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size)不能大于最大值512G。

show variables like '%innodb_log_file_size%';

redo log 寫入磁盤過程分析

redo log 從頭開始寫,寫完一個文件繼續寫另一個文件,寫到最后一個文件末尾就又回到第一個文件開頭循環寫,如下面這個圖所示。
在這里插入圖片描述
write pos 是當前記錄的位置,一邊寫一邊后移,寫到第 3 號文件末尾后就回到 0 號文件開頭。
checkpoint 是當前要擦除的位置,也是往后推移并且循環的,擦除記錄前要把記錄更新到數據文件里。
write pos 和 checkpoint 之間的部分就是空著的可寫部分,可以用來記錄新的操作。如果 write pos 追上checkpoint,表示redo log寫滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推進一下。
innodb_flush_log_at_trx_commit:這個參數控制 redo log 的寫入策略,它有三種可能取值:

  • 設置為0:表示每次事務提交時都只是把 redo log 留在 redo log buffer 中,數據庫宕機可能會丟失數據。
  • 設置為1(默認值):表示每次事務提交時都將 redo log 直接持久化到磁盤,數據最安全,不會因為數據庫宕機丟失數據,但是效率稍微差一點,線上系統推薦這個設置。
  • 設置為2:表示每次事務提交時都只是把 redo log 寫到操作系統的緩存page cache里,這種情況如果數據庫宕機是不會丟失數據的,但是操作系統如果宕機了,page cache里的數據還沒來得及寫入磁盤文件的話就會丟失數據。

InnoDB 有一個后臺線程,每隔 1 秒,就會把 redo log buffer 中的日志,調用 操作系統函數 write 寫到文件系統的 page cache,然后調用操作系統函數 fsync 持久化到磁盤文件。
redo log寫入策略參看下圖:
在這里插入圖片描述

# 查看innodb_flush_log_at_trx_commit參數值:
show variables like 'innodb_flush_log_at_trx_commit';
# 設置innodb_flush_log_at_trx_commit參數值(也可以在my.ini或my.cnf文件里配置):
set global innodb_flush_log_at_trx_commit=1;  

binlog二進制歸檔日志

binlog二進制日志記錄保存了所有執行過的修改操作語句,不保存查詢操作。如果 MySQL 服務意外停止,可通過二進制日志文件排查,用戶操作或表結構操作,從而來恢復數據庫數據。
啟動binlog記錄功能,會影響服務器性能,但如果需要恢復數據或主從復制功能,則好處則大于對服務器的影響。

# 查看binlog相關參數
show variables like '%log_bin%';

MySQL5.7 版本中,binlog默認是關閉的,8.0版本默認是打開的。上圖中log_bin的值是OFF就代表binlog是關閉狀態,打開binlog功能,需要修改配置文件my.ini(windows)或my.cnf(linux),然后重啟數據庫。
在配置文件中的[mysqld]部分增加如下配置:

# log-bin設置binlog的存放位置,可以是絕對路徑,也可以是相對路徑,這里寫的相對路徑,則binlog文件默認會放在data數據目錄下
log-bin=mysql-binlog
# Server Id是數據庫服務器id,隨便寫一個數都可以,這個id用來在mysql集群環境中標記唯一mysql服務器,集群環境中每臺mysql服務器的id不能一樣,不加啟動會報錯
server-id=1
# 其他配置
binlog_format = row # 日志文件格式,下面會詳細解釋
expire_logs_days = 15 # 執行自動刪除距離當前15天以前的binlog日志文件的天數, 默認為0, 表示不自動刪除
max_binlog_size = 200M # 單個binlog日志文件的大小限制,默認為 1GB

重啟數據庫后再去看data數據目錄會多出兩個文件,第一個就是binlog日志文件,第二個是binlog文件的索引文件,這個文件管理了所有的binlog文件的目錄。
在這里插入圖片描述
當然也可以執行命令查看有多少binlog文件

show binary logs;
show variables like '%log_bin%';

在這里插入圖片描述

log_bin:binlog日志是否打開狀態
log_bin_basename:是binlog日志的基本文件名,后面會追加標識來表示每一個文件,binlog日志文件會滾動增加
log_bin_index:指定的是binlog文件的索引文件,這個文件管理了所有的binlog文件的目錄。
sql_log_bin:sql語句是否寫入binlog文件,ON代表需要寫入,OFF代表不需要寫入。如果想在主庫上執行一些操作,但不復制到slave庫上,可以通過修改參數sql_log_bin來實現。比如說,模擬主從同步復制異常。

binlog 的日志格式

用參數 binlog_format 可以設置binlog日志的記錄格式,mysql支持三種格式類型:

  • STATEMENT:基于SQL語句的復制,每一條會修改數據的sql都會記錄到master機器的bin-log中,這種方式日志量小,節約IO開銷,提高性能,但是對于一些執行過程中才能確定結果的函數,比如UUID()、SYSDATE()等函數如果隨sql同步到slave機器去執行,則結果跟master機器執行的不一樣。
  • ROW:基于行的復制,日志中會記錄成每一行數據被修改的形式,然后在slave端再對相同的數據進行修改記錄下每一行數據修改的細節,可以解決函數、存儲過程等在slave機器的復制問題,但這種方式日志量較大,性能不如Statement。舉個例子,假設update語句更新10行數據,Statement方式就記錄這條update語句,Row方式會記錄被修改的10行數據。
  • MIXED:混合模式復制,實際就是前兩種模式的結合,在Mixed模式下,MySQL會根據執行的每一條具體的sql語句來區分對待記錄的日志形式,也就是在Statement和Row之間選擇一種,如果sql里有函數或一些在執行時才知道結果的情況,會選擇Row,其它情況選擇Statement,推薦使用這一種。

binlog寫入磁盤機制

binlog寫入磁盤機制主要通過 sync_binlog 參數控制,默認值是 0。

  • 為0的時候,表示每次提交事務都只 write 到page cache,由系統自行判斷什么時候執行 fsync 寫入磁盤。雖然性能得到提升,但是機器宕機,page cache里面的 binlog 會丟失。
  • 也可以設置為1,表示每次提交事務都會執行 fsync 寫入磁盤,這種方式最安全。
  • 還有一種折中方式,可以設置為N(N>1),表示每次提交事務都write 到page cache,但累積N個事務后才 fsync 寫入磁盤,這種如果機器宕機會丟失N個事務的binlog。

發生以下任何事件時, binlog日志文件會重新生成:

  • 服務器啟動或重新啟動
  • 服務器刷新日志,執行命令flush logs
  • 日志文件大小達到 max_binlog_size 值,默認值為 1GB

刪除 binlog 日志文件

刪除當前的binlog文件
reset master;
# 刪除指定日志文件之前的所有日志文件,下面這個是刪除6之前的所有日志文件,當前這個文件不刪除
purge master logs to 'mysql-binlog.000006';
# 刪除指定日期前的日志索引中binlog日志文件
purge master logs before '2023-01-21 14:00:00';

查看 binlog 日志文件

可以用mysql自帶的命令工具 mysqlbinlog 查看binlog日志內容

# 查看bin-log二進制文件(命令行方式,不用登錄mysql)
mysqlbinlog --no-defaults -v --base64-output=decode-rows D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000007 # 查看bin-log二進制文件(帶查詢條件)
mysqlbinlog --no-defaults -v --base64-output=decode-rows D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000007 start-datetime="2023-01-21 00:00:00" stop-datetime="2023-02-01 00:00:00" start-position="5000" stop-position="20000"

執行mysqlbinlog命令

mysqlbinlog --no-defaults -v --base64-output=decode-rows D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000007

查出來的binlog日志文件內容如下:

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#230127 21:13:51 server id 1  end_log_pos 123 CRC32 0x084f390f  Start: binlog v 4, server v 5.7.25-log created 230127 21:13:51 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
# at 123
#230127 21:13:51 server id 1  end_log_pos 154 CRC32 0x672ba207  Previous-GTIDs
# [empty]
# at 154
#230127 21:22:48 server id 1  end_log_pos 219 CRC32 0x8349d010  Anonymous_GTID  last_committed=0        sequence_number=1       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#230127 21:22:48 server id 1  end_log_pos 291 CRC32 0xbf49de02  Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1674825768/*!*/;
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=1342177280/*!*/;
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 291
#230127 21:22:48 server id 1  end_log_pos 345 CRC32 0xc4ab653e  Table_map: `test`.`account` mapped to number 99
# at 345
#230127 21:22:48 server id 1  end_log_pos 413 CRC32 0x54a124bd  Update_rows: table id 99 flags: STMT_END_F
### UPDATE `test`.`account`
### WHERE
###   @1=1
###   @2='lilei'
###   @3=1000
### SET
###   @1=1
###   @2='lilei'
###   @3=2000
# at 413
#230127 21:22:48 server id 1  end_log_pos 444 CRC32 0x23355595  Xid = 10
COMMIT/*!*/;
# at 444
。。。

能看到里面有具體執行的修改偽sql語句以及執行時的相關情況。

binlog日志文件恢復數據

用binlog日志文件恢復數據其實就是回放執行之前記錄在binlog文件里的sql,舉一個數據恢復的例子

# 先執行刷新日志的命令生成一個新的binlog文件mysql-binlog.000008,后面我們的修改操作日志都會記錄在最新的這個文件里
flush logs;
# 執行兩條插入語句
INSERT INTO `test`.`account` (`id`, `name`, `balance`) VALUES ('4', 'zhuge', '666');
INSERT INTO `test`.`account` (`id`, `name`, `balance`) VALUES ('5', 'zhuge1', '888');
# 假設現在誤操作執行了一條刪除語句把剛新增的兩條數據刪掉了
delete from account where id > 3;

現在需要恢復被刪除的兩條數據,我們先查看binlog日志文件

mysqlbinlog --no-defaults -v --base64-output=decode-rows D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000008

文件內容如下:

。。。。。。
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#230127 23:32:24 server id 1  end_log_pos 291 CRC32 0x4528234f  Query   thread_id=5     exec_time=0     error_code=0
SET TIMESTAMP=1674833544/*!*/;
SET @@session.pseudo_thread_id=5/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1342177280/*!*/;
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 291
#230127 23:32:24 server id 1  end_log_pos 345 CRC32 0x7482741d  Table_map: `test`.`account` mapped to number 99
# at 345
#230127 23:32:24 server id 1  end_log_pos 396 CRC32 0x5e443cf0  Write_rows: table id 99 flags: STMT_END_F
### INSERT INTO `test`.`account`
### SET
###   @1=4
###   @2='zhuge'
###   @3=666
# at 396
#230127 23:32:24 server id 1  end_log_pos 427 CRC32 0x8a0d8a3c  Xid = 56
COMMIT/*!*/;
# at 427
#230127 23:32:40 server id 1  end_log_pos 492 CRC32 0x5261a37e  Anonymous_GTID  last_committed=1        sequence_number=2       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 492
#230127 23:32:40 server id 1  end_log_pos 564 CRC32 0x01086643  Query   thread_id=5     exec_time=0     error_code=0
SET TIMESTAMP=1674833560/*!*/;
BEGIN
/*!*/;
# at 564
#230127 23:32:40 server id 1  end_log_pos 618 CRC32 0xc26b6719  Table_map: `test`.`account` mapped to number 99
# at 618
#230127 23:32:40 server id 1  end_log_pos 670 CRC32 0x8e272176  Write_rows: table id 99 flags: STMT_END_F
### INSERT INTO `test`.`account`
### SET
###   @1=5
###   @2='zhuge1'
###   @3=888
# at 670
#230127 23:32:40 server id 1  end_log_pos 701 CRC32 0xb5e63d00  Xid = 58
COMMIT/*!*/;
# at 701
#230127 23:34:23 server id 1  end_log_pos 766 CRC32 0xa0844501  Anonymous_GTID  last_committed=2        sequence_number=3       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 766
#230127 23:34:23 server id 1  end_log_pos 838 CRC32 0x687bdf88  Query   thread_id=7     exec_time=0     error_code=0
SET TIMESTAMP=1674833663/*!*/;
BEGIN
/*!*/;
# at 838
#230127 23:34:23 server id 1  end_log_pos 892 CRC32 0x4f7b7d6a  Table_map: `test`.`account` mapped to number 99
# at 892
#230127 23:34:23 server id 1  end_log_pos 960 CRC32 0xc47ac777  Delete_rows: table id 99 flags: STMT_END_F
### DELETE FROM `test`.`account`
### WHERE
###   @1=4
###   @2='zhuge'
###   @3=666
### DELETE FROM `test`.`account`
### WHERE
###   @1=5
###   @2='zhuge1'
###   @3=888
# at 960
#230127 23:34:23 server id 1  end_log_pos 991 CRC32 0x386699fe  Xid = 65
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
。。。。。。

找到兩條插入數據的sql,每條sql的上下都有BEGIN和COMMIT,我們找到第一條sql BEGIN前面的文件位置標識 at 219(這是文件的位置標識),再找到第二條sql COMMIT后面的文件位置標識 at 701
我們可以根據文件位置標識來恢復數據,執行如下sql:

mysqlbinlog  --no-defaults --start-position=219 --stop-position=701 --database=test D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000009 | mysql -uroot -p123456 -v test# 補充一個根據時間來恢復數據的命令,我們找到第一條sql BEGIN前面的時間戳標記 SET TIMESTAMP=1674833544,再找到第二條sql COMMIT后面的時間戳標記 SET TIMESTAMP=1674833663,轉成datetime格式
mysqlbinlog  --no-defaults --start-datetime="2023-1-27 23:32:24" --stop-datetime="2023-1-27 23:34:23" --database=test D:/dev/mysql-5.7.25-winx64/data/mysql-binlog.000009 | mysql -uroot -p123456 -v test

被刪除數據被恢復!
注意:如果要恢復大量數據,比如程序員經常說的刪庫跑路的話題,假設我們把數據庫所有數據都刪除了要怎么恢復了,如果數據庫之前沒有備份,所有的binlog日志都在的話,就從binlog第一個文件開始逐個恢復每個binlog文件里的數據,這種一般不太可能,因為binlog日志比較大,早期的binlog文件會定期刪除的,所以一般不可能用binlog文件恢復整個數據庫的。
一般我們推薦的是每天(在凌晨后)需要做一次全量數據庫備份,那么恢復數據庫可以用最近的一次全量備份再加上備份時間點之后的binlog來恢復數據。
備份數據庫一般可以用mysqldump 命令工具

mysqldump -u root 數據庫名>備份文件名;   #備份整個數據庫
mysqldump -u root 數據庫名 表名字>備份文件名;  #備份整個表mysql -u root test < 備份文件名 #恢復整個數據庫,test為數據庫名稱,需要自己先建一個數據庫test

為什么會有redo log和binlog兩份日志呢?
因為最開始 MySQL 里并沒有 InnoDB 引擎。MySQL 自帶的引擎是 MyISAM,但是MyISAM 沒有 crash-safe 的能力,binlog 日志只能用于歸檔。而 InnoDB 是另一個公司以插件形式引入 MySQL 的,既然只依靠 binlog 是沒有 crash-safe 能力的,所以InnoDB 使用另外一套日志系統——也就是 redo log 來實現 crash-safe 能力。
有了 redo log,InnoDB 就可以保證即使數據庫發生異常重啟,之前提交的記錄都不會丟失,這個能力稱為crash-safe。
undo log回滾日志
InnoDB對undo log文件的管理采用段的方式,也就是回滾段(rollback segment) 。每個回滾段記錄了 1024 個 undo log segment ,每個事務只會使用一個undo log segment。
在MySQL5.5的時候,只有一個回滾段,那么最大同時支持的事務數量為1024個。在MySQL 5.6開始,InnoDB支持最大128個回滾段,故其支持同時在線的事務限制提高到了 128*1024 。

innodb_undo_directory:設置undo log文件所在的路徑。該參數的默認值為"./",即innodb數據文件存儲位置,目錄下ibdata1文件就是undo log存儲的位置。
innodb_undo_logs: 設置undo log文件內部回滾段的個數,默認值為128。
innodb_undo_tablespaces: 設置undo log文件的數量,這樣回滾段可以較為平均地分布在多個文件中。設置該參數后,會在路徑innodb_undo_directory看到undo為前綴的文件。

undo log日志什么時候刪除

新增類型的,在事務提交之后就可以清除掉了。
修改類型的,事務提交之后不能立即清除掉,這些日志會用于mvcc。只有當沒有事務用到該版本信息時才可以清除。

為什么Mysql不能直接更新磁盤上的數據而設置這么一套復雜的機制來執行SQL了?

因為來一個請求就直接對磁盤文件進行隨機讀寫,然后更新磁盤文件里的數據性能可能相當差。
因為磁盤隨機讀寫的性能是非常差的,所以直接更新磁盤文件是不能讓數據庫抗住很高并發的。
Mysql這套機制看起來復雜,但它可以保證每個更新請求都是更新內存BufferPool,然后順序寫日志文件,同時還能保證各種異常情況下的數據一致性。
更新內存的性能是極高的,然后順序寫磁盤上的日志文件的性能也是非常高的,要遠高于隨機讀寫磁盤文件。
正是通過這套機制,才能讓我們的MySQL數據庫在較高配置的機器上每秒可以抗下幾干甚至上萬的讀寫請求。

錯誤日志

Mysql還有一個比較重要的日志是錯誤日志,它記錄了數據庫啟動和停止,以及運行過程中發生任何嚴重錯誤時的相關信息。當數據庫出現任何故障導致無法正常使用時,建議首先查看此日志。
在MySQL數據庫中,錯誤日志功能是默認開啟的,而且無法被關閉。

# 查看錯誤日志存放位置
show variables like '%log_error%';

通用查詢日志

通用查詢日志記錄用戶的所有操作,包括啟動和關閉MySQL服務、所有用戶的連接開始時間和截止時間、發給 MySQL 數據庫服務器的所有 SQL 指令等,如select、show等,無論SQL的語法正確還是錯誤、也無論SQL執行成功還是失敗,MySQL都會將其記錄下來。
通用查詢日志用來還原操作時的具體場景,可以幫助我們準確定位一些疑難問題,比如重復支付等問題。
general_log:是否開啟日志參數,默認為OFF,處于關閉狀態,因為開啟會消耗系統資源并且占用磁盤空間。一般不建議開啟,只在需要調試查詢問題時開啟。
general_log_file:通用查詢日志記錄的位置參數。

show variables like '%general_log%';
# 打開通用查詢日志
SET GLOBAL general_log=on;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87243.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87243.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87243.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MCP基本概念

基本概念 現在大模型交互的熱門形式&#xff1a; 第一、Agent與Tools(工具)的交互Agent需要調用外部工具和APl、訪問數據庫、執行代碼等。> MCP 第二、Agent與Agent(其他智能體或用戶)的交互Agent需要理解其他Agent的意圖、協同完成任務、與用戶進行自然的對話。 > A2A…

Docker容器相關命令介紹和示例

Docker 容器是鏡像的運行實例。以下是常用的 Docker 容器命令及其示例&#xff1a; 1. 運行容器 docker run [選項] <鏡像名> [命令]常用選項&#xff1a; -d&#xff1a;后臺運行&#xff08;守護模式&#xff09;-it&#xff1a;交互式終端--name&#xff1a;指定容…

【Akshare】高效下載股票和ETF數據

在量化投資與金融數據分析的世界里&#xff0c;獲取高質量的市場數據是構建有效策略的關鍵。Python庫Akshare為我們提供了一個強大且易于使用的接口&#xff0c;可以輕松地從網絡上抓取各類金融數據。本文將詳細介紹如何利用Akshare下載股票和ETF的歷史行情數據。 安裝Akshare…

分布式--3--分布式事務

1 簡介 事務在單系統中的表現&#xff1a;多次數據庫操作用事務進行管理&#xff0c;來保證ACID原則。 但是如果各個模塊都是單獨獨立出來的微服務&#xff0c;進行了分布式部署&#xff0c;單系統里的事務將不能保證各個數據庫操作的一致性&#xff0c;因此就需要分布式事務來…

不同建模方式的介紹 RTL建模筆記(1)

說明&#xff1a;該專欄"RTL建模筆記"是《RTL Modeling with SystemVerilog for Simulation and Synthesis》的翻譯&#xff1b;該筆記略過了第一章第一小節中背景介紹內容&#xff0c;以及第二小節前面部分的門級、RTL級建模介紹&#xff0c;對于后續學習不影響。 …

<13>-MySQL用戶管理

目錄 一&#xff0c;用戶管理操作 1&#xff0c;創建用戶 2&#xff0c;查詢用戶 3&#xff0c;修改密碼 4&#xff0c;刪除用戶 二&#xff0c;數據庫權限 1&#xff0c;用戶授權 2&#xff0c;回收權限 一&#xff0c;用戶管理操作 1&#xff0c;創建用戶 --創建用戶…

如何使用超低噪聲電源提高AD 時鐘電路質量,改善超聲系統的圖像質量

超聲波技術是醫療診斷和其他應用中廣泛使用的無創工具&#xff0c;已經從靜態圖像進化到動態圖像&#xff0c;從黑白呈現變為彩色多普勒圖像。這些重大進步主要是由于引入了數字超聲技術。雖然這些進步提高了超聲成像的有效性和通用性&#xff0c;但同樣重要的是&#xff0c;這…

【解決方案】Kali 2022.3修復倉庫密鑰一鍵安裝docker,docker compose

1、Kali 2022.3 2、一鍵安裝docker&#xff0c;docker compose #!/bin/bashecho " 安全的Kali Docker安裝腳本 "# 備份重要配置 cp /etc/apt/sources.list /etc/apt/sources.list.backup.$(date %Y%m%d)# 修復Kali倉庫配置 echo "修復Kali倉庫配置..." ca…

Transformer、RNN (循環神經網絡) 和 CNN (卷積神經網絡)的區別

我們來詳細對比一下 Transformer、RNN (循環神經網絡) 和 CNN (卷積神經網絡) 這三種在深度學習中極其重要的架構&#xff0c;并通過具體例子說明它們的區別。 核心區別總結&#xff1a; 處理數據的方式&#xff1a; CNN: 專注于局部特征和空間/時間模式。通過卷積核在輸入數據…

408第二季 - 組成原理 - 數據類型轉換

這章內容會比較少 閑聊 如果題目說把8位改成4位&#xff0c;你保留低位就行了 這里保留的是0101 然后是有符號數和無符號數的轉換 機器數就是二進制長什么樣子 然后就是小數點是不參與存儲的 然后簡單看看代碼 這是short就說明是有符號數 unsigned就是說明是無符號數 然后y…

讓 Deepseek 寫電器電費計算器(html版本)

以下是一個簡單的電器電費計算器的HTML和CSS代碼&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…

react_flow自定義節點、邊——使用darg布局樹狀結構

文章目錄 ?前言?引入react-flow?自定義節點nodeType?自定義邊edgeType?添加節點?inscode代碼塊?結束 ?前言 大家好&#xff0c;我是yma16&#xff0c;本文分享 前端 ——react_flow自定義節點、邊——使用darg布局樹狀結構。 自定義效果 可以自定義節點、邊、線條流動…

word表格批量轉excel,提取表格數據到excel

本文將帶你一步步實現一個將 Word 中的表格內容批量提取并轉換為 Excel 文件的自動化工具&#xff0c;適用于需要手動復制粘貼數據到excel的場景 假設我們有這樣的表格在word中&#xff0c;圖片世放在excel中便于截圖&#xff0c;現在需要將表格中有顏色的數據提取到對應的exce…

day2課程

1.添加pinia到Vue項目 2.counter基礎使用 3.getters和異步action 4.storeToRefs和調試 5.項目初始化和git管理 6.別名路徑聯想設置 7.elementsPlus自動按需導入配置 這個項目使用的是按需引入 1.安裝包管理器 npm install element-plus --save 2.按需引入 npm install -D unp…

Vue3 + TypeScript + Element Plus 設置表格行背景顏色

技術要點&#xff1a; 1、使用 :row-class-name"setRowClassName" 設置表格行類名 2、不能同時使用 stripe 3、設置行類名的樣式 應用效果&#xff1a; 同時使用 stripe 出來的效果&#xff1a; 參考代碼&#xff1a; ReagentTable.vue <script setup lang&…

山東大學 軟件項目管理知識點總結

軟件項目管理背誦總結 將老師所發ppt的知識點整理&#xff0c;方便查閱與背誦。 文章目錄 軟件項目管理背誦總結1. 概述1.1 什么是項目&#xff1f;1.2 項目有那些特征&#xff1f;1.3 項目于日常工作有什么區別&#xff1f;1.4 如何衡量一個項目是否成功&#xff1f;1.5 軟件項…

css基礎筆記簡潔版1

&#x1f4d8; CSS 基礎筆記 1 一、CSS 簡介 CSS&#xff08;層疊樣式表&#xff09;用于為網頁添加樣式&#xff0c;實現結構與樣式分離&#xff0c;能夠控制顏色、字體、布局、位置、動畫等視覺效果。 二、基本語法 選擇器 {屬性1: 值1;屬性2: 值2; }說明&#xff1a; 選…

reactor模型學習

學習鏈接 狂野架構師第四期netty視頻 - B站視頻 狂野架構師訓練營6期 - B站視頻 Netty學習example示例&#xff08;含官方示例代碼&#xff09; LG-Netty學習 【硬核】肝了一月的Netty知識點 - 啟動過程寫的很詳細 Reactor模型講解 一文搞懂Reactor模型與實現 高性能網絡編…

應用探析|千眼狼高速攝像機、sCMOS相機、DIC測量、PIV測量在光學領域的應用

2025&#xff0c;長春&#xff0c;中國光學學會學術大會。中科視界攜千眼狼品牌四大科學儀器高速攝像機、sCMOS科學相機、DIC應變測量系統、PIV流場測量系統亮相&#xff0c;在光學領域多個細分研究方向承載科學實驗的感知與測量任務。 1先進制造技術及其應用 激光切割、激光焊…

Kafka 4.0.0集群部署

Kafka 4.0.0集群部署 1.1 關閉防火墻和 selinux 關閉防火墻 systemctl stop firewalld.service systemctl disable firewalld.service關閉selinux setenforce 0 #&#xff08;臨時生效&#xff09; sed -i s/^SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config #&…