最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL Undo/Redo Log使用詳解

 更新時(shí)間:2026年03月09日 08:20:52   作者:蕭曵 丶  
本文系統(tǒng)分析了MySQL中RedoLog和UndoLog的核心機(jī)制與應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、核心概念對比

特性Redo LogUndo Log
主要目的保證事務(wù)的持久性保證事務(wù)的原子性和MVCC
寫入時(shí)機(jī)事務(wù)進(jìn)行中,數(shù)據(jù)修改前事務(wù)進(jìn)行中,數(shù)據(jù)修改后
內(nèi)容記錄物理修改操作記錄邏輯修改前的數(shù)據(jù)
存儲(chǔ)方式順序?qū)懭?,循環(huán)覆蓋隨機(jī)寫入,按需清理
生命周期事務(wù)提交后,數(shù)據(jù)刷盤后可清理事務(wù)提交后,但需保留至沒有事務(wù)依賴
恢復(fù)方向前滾(redo)回滾(undo)
文件ib_logfile0, ib_logfile1ibdata1或獨(dú)立表空間

二、Redo Log詳細(xì)原理

1.物理結(jié)構(gòu)

# 查看Redo Log配置
SHOW VARIABLES LIKE 'innodb_log%';
# 重要參數(shù):
# innodb_log_file_size = 每個(gè)文件大?。J(rèn)48M-2G)
# innodb_log_files_in_group = 文件數(shù)量(默認(rèn)2)
# innodb_log_buffer_size = 緩沖區(qū)大小(默認(rèn)16M)

2.寫入流程(兩階段提交)

-- 示例:UPDATE users SET balance=200 WHERE id=1;

1. 內(nèi)存階段:
    - 修改Buffer Pool中的數(shù)據(jù)頁
    - 將修改記錄寫入Log Buffer
    
2. 準(zhǔn)備階段(Prepare):
    - Log Buffer中的Redo記錄刷入Redo Log文件
    - 此時(shí)Redo Log狀態(tài)為"prepare"
    
3. 提交階段(Commit):
    - Binlog寫入完成
    - Redo Log狀態(tài)改為"commit"
    - 事務(wù)提交成功

3.Checkpoint機(jī)制

# Checkpoint過程示意
def checkpoint_process():
    # 1. 找到最老的臟頁LSN(Log Sequence Number)
    oldest_dirty_lsn = find_oldest_dirty_page()
    
    # 2. 將這個(gè)LSN寫入Redo Log頭
    write_checkpoint_to_redo(oldest_dirty_lsn)
    
    # 3. 刷新臟頁到磁盤
    flush_dirty_pages_to_disk()
    
    # 4. 清理Redo Log空間
    # 從checkpoint前的Redo Log可以安全覆蓋

三、Undo Log詳細(xì)原理

1.存儲(chǔ)結(jié)構(gòu)

-- Undo Log段管理
CREATE TABLE t (
    id INT PRIMARY KEY,
    name VARCHAR(20),
    balance DECIMAL(10,2)
) ENGINE=InnoDB;

-- Undo Log包含:
-- 1. 回滾指針:DB_ROLL_PTR(指向舊版本)
-- 2. 事務(wù)ID:DB_TRX_ID(最近修改的事務(wù)ID)
-- 3. 刪除標(biāo)記:DELETED_BIT

2.版本鏈構(gòu)建

# 數(shù)據(jù)行的版本鏈?zhǔn)疽?br />當(dāng)前行 (id=1, name='Alice', balance=100)
    ↓ roll_ptr
Undo Log 1: (balance=50, trx_id=100)  ← UPDATE操作前的版本
    ↓ roll_ptr  
Undo Log 2: (name='Bob', trx_id=80)   ← 更早的UPDATE
    ↓ roll_ptr
NULL (初始版本)

3.MVCC實(shí)現(xiàn)

-- 讀已提交(Read Committed)隔離級別下的可見性判斷
SELECT * FROM users WHERE id=1;

-- InnoDB判斷流程:
-- 1. 獲取當(dāng)前事務(wù)ID: current_trx_id
-- 2. 獲取當(dāng)前活躍事務(wù)列表: active_trx_list
-- 3. 從當(dāng)前行開始遍歷版本鏈:
--    - 如果 trx_id < current_trx_id 且 trx_id不在活躍列表中
--      且 trx_id <= up_limit_id(快照上限)
--    - 則該版本對當(dāng)前事務(wù)可見
-- 4. 否則繼續(xù)查找更早版本

四、實(shí)際應(yīng)用場景

場景1:銀行轉(zhuǎn)賬事務(wù)

START TRANSACTION;
-- 步驟1:A賬戶扣款
UPDATE accounts SET balance=balance-100 WHERE id=1;
-- Undo Log記錄: (balance=原始值, trx_id=當(dāng)前事務(wù))
-- Redo Log記錄: 頁面修改信息

-- 步驟2:B賬戶入賬  
UPDATE accounts SET balance=balance+100 WHERE id=2;
-- Undo Log記錄: (balance=原始值, trx_id=當(dāng)前事務(wù))
-- Redo Log記錄: 頁面修改信息

COMMIT;
-- Binlog寫入 → Redo Log狀態(tài)改為commit

恢復(fù)場景

  • 如果在COMMIT前崩潰:

    • Redo Log處于prepare狀態(tài)

    • 重啟后根據(jù)Binlog決定是否提交

    • 使用Undo Log回滾未提交的修改

  • 如果在COMMIT后崩潰:

    • Redo Log為commit狀態(tài)

    • 重啟后重做已提交的事務(wù)

場景2:長事務(wù)問題

-- 危險(xiǎn)的長時(shí)間查詢
START TRANSACTION;
SELECT * FROM large_table WHERE ... FOR UPDATE;
-- 執(zhí)行復(fù)雜業(yè)務(wù)邏輯(耗時(shí)10分鐘)
-- ... 
COMMIT;

-- 問題:
-- 1. Undo Log無法清理,導(dǎo)致undo表空間膨脹
-- 2. 阻塞Purge線程
-- 3. 可能觸發(fā)“事務(wù)ID耗盡”問題

監(jiān)控腳本

-- 監(jiān)控長時(shí)間運(yùn)行的事務(wù)
SELECT 
    trx_id,
    trx_started,
    TIMEDIFF(NOW(), trx_started) AS duration,
    trx_state,
    trx_operation_state
FROM information_schema.INNODB_TRX
WHERE TIMEDIFF(NOW(), trx_started) > '00:05:00'
ORDER BY trx_started;

-- 監(jiān)控Undo Log使用
SHOW ENGINE INNODB STATUS\G
-- 查看"TRANSACTIONS"部分

場景3:批量數(shù)據(jù)處理優(yōu)化

-- 錯(cuò)誤的批量更新(產(chǎn)生大量Undo)
START TRANSACTION;
UPDATE large_table SET status=1 WHERE create_date < '2024-01-01';
-- 影響100萬行,產(chǎn)生大量Undo Log
COMMIT;

-- 優(yōu)化的批量更新
SET AUTOCOMMIT=0;
SET UNIQUE_CHECKS=0;
SET FOREIGN_KEY_CHECKS=0;

-- 分批次處理
DECLARE done INT DEFAULT FALSE;
DECLARE batch_size INT DEFAULT 1000;
DECLARE last_id INT DEFAULT 0;

REPEAT
    START TRANSACTION;
    
    UPDATE large_table 
    SET status=1 
    WHERE id > last_id 
    AND create_date < '2024-01-01'
    LIMIT batch_size;
    
    SET last_id = LAST_INSERT_ID();
    
    COMMIT;  -- 每個(gè)批次提交,釋放Undo
    
    SELECT SLEEP(0.1);  -- 避免過度消耗資源
    
UNTIL ROW_COUNT() = 0 END REPEAT;

SET AUTOCOMMIT=1;
SET UNIQUE_CHECKS=1;
SET FOREIGN_KEY_CHECKS=1;

五、性能優(yōu)化實(shí)戰(zhàn)

1.Redo Log優(yōu)化配置

# my.cnf配置示例
[mysqld]
# Redo Log文件大小,建議設(shè)置為緩沖池的1/4到1/2
# 對于8G內(nèi)存,Buffer Pool通常6G,Redo Log設(shè)為2G
innodb_log_file_size = 2G
innodb_log_files_in_group = 4  # 總大小=2G*4=8G

# Log Buffer大小,大事務(wù)可適當(dāng)調(diào)大
innodb_log_buffer_size = 64M

# 刷盤策略,根據(jù)數(shù)據(jù)安全需求選擇
# 1-最安全,每次提交都刷盤(默認(rèn))
# 2-折中,每次提交寫OS緩存,每秒刷盤
# 0-性能最好,每秒刷盤,可能丟失1秒數(shù)據(jù)
innodb_flush_log_at_trx_commit = 1

2.Undo表空間管理

-- MySQL 8.0+ 獨(dú)立Undo表空間
-- 查看Undo配置
SELECT * FROM information_schema.INNODB_TABLESPACES 
WHERE SPACE_TYPE = 'Undo';

-- 監(jiān)控Undo空間使用
SELECT 
    tablespace_name,
    file_size / 1024 / 1024 AS file_size_mb,
    allocated_size / 1024 / 1024 AS allocated_mb
FROM information_schema.FILES
WHERE file_name LIKE '%undo%';

-- 設(shè)置Undo表空間自動(dòng)清理
SET GLOBAL innodb_undo_log_truncate = ON;
SET GLOBAL innodb_max_undo_log_size = 1 * 1024 * 1024 * 1024;  -- 1GB
SET GLOBAL innodb_purge_rseg_truncate_frequency = 128;

3.高并發(fā)寫入優(yōu)化

-- 場景:秒殺活動(dòng),大量并發(fā)寫入
-- 問題:Redo Log成為瓶頸

-- 解決方案1:臨時(shí)調(diào)整刷盤策略(活動(dòng)期間)
SET GLOBAL innodb_flush_log_at_trx_commit = 2;
-- 活動(dòng)結(jié)束后恢復(fù)為1

-- 解決方案2:組提交優(yōu)化
-- MySQL已自動(dòng)支持,確保參數(shù)合理
SHOW VARIABLES LIKE 'binlog_group%';
SHOW VARIABLES LIKE 'innodb_flush_log_at_timeout';

-- 解決方案3:拆分熱點(diǎn)數(shù)據(jù)
-- 將熱點(diǎn)賬戶分散到不同數(shù)據(jù)頁
UPDATE account_001 SET ... WHERE user_id=1;  -- 分表

六、故障恢復(fù)實(shí)戰(zhàn)

場景:Redo Log損壞恢復(fù)

# 1. 檢查Redo Log狀態(tài)
mysql> SHOW ENGINE INNODB STATUS\G

# 2. 如果有備份,優(yōu)先使用備份恢復(fù)
# 使用Percona XtraBackup或mysqldump備份

# 3. 強(qiáng)制恢復(fù)模式(謹(jǐn)慎使用)
# 在my.cnf中添加
[mysqld]
innodb_force_recovery = 1  # 1-6,數(shù)字越大越激進(jìn)

# 4. 恢復(fù)步驟
# 4.1 停止MySQL
sudo systemctl stop mysql

# 4.2 備份原數(shù)據(jù)文件
cp -r /var/lib/mysql /var/lib/mysql_backup

# 4.3 移除損壞的Redo Log
mv /var/lib/mysql/ib_logfile* /tmp/

# 4.4 啟動(dòng)MySQL(會(huì)自動(dòng)創(chuàng)建新的Redo Log)
sudo systemctl start mysql

# 4.5 使用mysqlbinlog恢復(fù)未同步的數(shù)據(jù)
mysqlbinlog mysql-bin.000001 | mysql -u root -p

七、監(jiān)控與維護(hù)腳本

-- 1. Redo Log監(jiān)控
SELECT 
    'Redo Log' AS metric,
    CONCAT(ROUND(SUM(LENGTH)/1024/1024, 2), ' MB') AS current_size,
    CONCAT(ROUND(variable_value/1024/1024, 2), ' MB') AS configured_size,
    ROUND(SUM(LENGTH)*100/variable_value, 2) AS usage_percent
FROM information_schema.INNODB_BUFFER_PAGE
JOIN information_schema.GLOBAL_VARIABLES 
    ON variable_name = 'innodb_log_file_size'
WHERE PAGE_TYPE LIKE 'IBUF%'
GROUP BY variable_value;

-- 2. Undo空間監(jiān)控
SELECT 
    FORMAT_BYTES(SUM(current_size)) AS active_undo_size,
    FORMAT_BYTES(SUM(undo_size)) AS total_undo_size,
    COUNT(*) AS undo_segments,
    ROUND(SUM(current_size)*100/SUM(undo_size), 2) AS usage_pct
FROM information_schema.INNODB_METRICS
WHERE NAME LIKE '%undo%';

-- 3. 長事務(wù)和Undo關(guān)聯(lián)查詢
SELECT 
    r.trx_id AS waiting_trx_id,
    r.trx_mysql_thread_id AS waiting_thread,
    TIMEDIFF(NOW(), r.trx_started) AS wait_time,
    b.trx_id AS blocking_trx_id,
    b.trx_mysql_thread_id AS blocking_thread,
    bl.lock_table AS locked_table
FROM information_schema.INNODB_LOCK_WAITS w
INNER JOIN information_schema.INNODB_TRX b 
    ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.INNODB_TRX r 
    ON r.trx_id = w.requesting_trx_id
INNER JOIN information_schema.INNODB_LOCKS bl 
    ON bl.lock_id = w.blocking_lock_id;

八、最佳實(shí)踐總結(jié)

Redo Log優(yōu)化:

  • 大小配置:總大小 = Buffer Pool的25%-50%
  • IO優(yōu)化:使用SSD,單獨(dú)磁盤存放Redo Log
  • 監(jiān)控告警:設(shè)置Redo Log切換頻率告警(> 20次/小時(shí)需擴(kuò)容)

Undo Log優(yōu)化:

  • 避免長事務(wù):事務(wù)時(shí)間控制在5秒內(nèi)
  • 定期清理:啟用innodb_undo_log_truncate
  • 版本控制:及時(shí)提交只讀事務(wù),釋放快照

通用建議:

  • 定期備份:Redo Log不是備份,需配合Binlog和物理備份
  • 壓力測試:在高并發(fā)場景測試Redo/Undo配置
  • 版本升級:MySQL 8.0在Undo管理上有顯著改進(jìn)
  • 監(jiān)控完備:使用Prometheus+Granafa監(jiān)控Redo/Undo指標(biāo)

故障預(yù)案:

  • 保持Redo Log在獨(dú)立磁盤
  • 定期測試恢復(fù)流程
  • 設(shè)置合理的innodb_force_recovery預(yù)案
  • 重要業(yè)務(wù)開啟雙1配置(sync_binlog=1innodb_flush_log_at_trx_commit=1

通過深入理解Redo和Undo Log的工作原理,可以更好地設(shè)計(jì)數(shù)據(jù)庫架構(gòu)、優(yōu)化性能,并在故障時(shí)快速恢復(fù),確保業(yè)務(wù)的連續(xù)性和數(shù)據(jù)的安全性。

到此這篇關(guān)于MySQL Undo/Redo Log使用詳解的文章就介紹到這了,更多相關(guān)MySQL Undo/Redo Log內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL窗口函數(shù)OVER使用示例詳細(xì)講解

    MySQL窗口函數(shù)OVER使用示例詳細(xì)講解

    這篇文章主要介紹了MySQL窗口函數(shù)OVER()用法及說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • MySQL整型數(shù)據(jù)溢出的解決方法

    MySQL整型數(shù)據(jù)溢出的解決方法

    這篇文章主要介紹了MySQL整型數(shù)據(jù)溢出的解決方法,本文出現(xiàn)整型溢出的mysql版本是5.1,5.1下整型溢出不會(huì)報(bào)錯(cuò),而會(huì)變成負(fù)數(shù),需要的朋友可以參考下
    2014-07-07
  • mysql SELECT FOR UPDATE語句使用示例

    mysql SELECT FOR UPDATE語句使用示例

    本文介紹在mysql中使用mysql SELECT FOR UPDATE 語句時(shí)的一些問題與解決辦法
    2013-11-11
  • MySQL讀寫分離的項(xiàng)目時(shí)間實(shí)踐

    MySQL讀寫分離的項(xiàng)目時(shí)間實(shí)踐

    本文主要介紹了MySQL數(shù)據(jù)庫的讀寫分離技術(shù),包括一主一從和雙主雙從兩種架構(gòu),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-03-03
  • 一文詳解小白也能懂的SQL高效去重技巧

    一文詳解小白也能懂的SQL高效去重技巧

    當(dāng)你的數(shù)據(jù)中有重復(fù)記錄時(shí),如何快速找到每個(gè)分組的最新一條,一個(gè)優(yōu)雅的SQL查詢就能解決,下面小編就來和大家詳細(xì)講解一下SQL高效的去重技巧吧
    2025-07-07
  • mysql多主雙向和級聯(lián)復(fù)制

    mysql多主雙向和級聯(lián)復(fù)制

    這篇文章主要介紹了mysql多主雙向和級聯(lián)復(fù)制,架構(gòu)內(nèi)各個(gè)庫均同時(shí)開啟binlog的master和slave,主主庫額外開啟級聯(lián)復(fù)制開關(guān),下面詳細(xì)內(nèi)容,需要的小伙伴可以參考一下
    2022-01-01
  • mysql千萬級數(shù)據(jù)量根據(jù)索引優(yōu)化查詢速度的實(shí)現(xiàn)

    mysql千萬級數(shù)據(jù)量根據(jù)索引優(yōu)化查詢速度的實(shí)現(xiàn)

    這篇文章主要介紹了mysql千萬級數(shù)據(jù)量根據(jù)索引優(yōu)化查詢速度的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • mysql中的判斷函數(shù)和分支語句詳解

    mysql中的判斷函數(shù)和分支語句詳解

    本文介紹了SQL中常用的判斷函數(shù)和分支語句,判斷函數(shù)包括if()、ifnull()以及nullif(),用于處理數(shù)據(jù)判斷和空值處理,分支語句分為多條件判斷和固定值判斷,便于根據(jù)不同條件執(zhí)行相應(yīng)邏輯,這些功能在數(shù)據(jù)處理和查詢中非常實(shí)用
    2024-10-10
  • MySQL之MyISAM存儲(chǔ)引擎的非聚簇索引詳解

    MySQL之MyISAM存儲(chǔ)引擎的非聚簇索引詳解

    這篇文章主要為大家詳細(xì)介紹了MySQL之MyISAM存儲(chǔ)引擎的非聚簇索引,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • MySQL修改時(shí)間添加時(shí)間自動(dòng)更新的兩種方法

    MySQL修改時(shí)間添加時(shí)間自動(dòng)更新的兩種方法

    這篇文章主要介紹了MySQL修改時(shí)間添加時(shí)間自動(dòng)更新的兩種方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09

最新評論

安新县| 林甸县| 和静县| 三门县| 五台县| 托里县| 宜黄县| 景泰县| 湟源县| 兰西县| 政和县| 万盛区| 南丹县| 错那县| 大新县| 广水市| 南雄市| 永嘉县| 日照市| 邵武市| 乳源| 富平县| 泸西县| 武穴市| 常宁市| 平和县| 类乌齐县| 理塘县| 六安市| 特克斯县| 隆昌县| 庆云县| 健康| 达州市| 交城县| 普宁市| 淮南市| 遂溪县| 涪陵区| 电白县| 托克托县|