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

從源碼到實戰(zhàn)盤點MySQL中不寫B(tài)inlog的N種場景

 更新時間:2026年02月24日 09:14:01   作者:Seal^_^  
Binlog(二進制日志)是MySQL的核心組件,負責(zé)記錄數(shù)據(jù)變更,支撐著主從復(fù)制、數(shù)據(jù)恢復(fù)等重要功能,本文將深入MySQL源碼,徹底解析哪些場景下MySQL不會寫入binlog,希望對大家有所幫助

引言

Binlog(二進制日志)是MySQL的核心組件,負責(zé)記錄數(shù)據(jù)變更,支撐著主從復(fù)制、數(shù)據(jù)恢復(fù)等重要功能。但你是否遇到過這樣的疑問:

  • 為什么mysql.slow_log表的變更不會同步到從庫?
  • SET sql_log_bin = 0到底做了什么?
  • performance_schema的數(shù)據(jù)變化會記錄到binlog嗎?

本文將深入MySQL源碼,徹底解析哪些場景下MySQL不會寫入binlog,并通過源碼級別的分析,讓你不僅知其然,更知其所以然。

1. Binlog寫入的核心判斷邏輯

在MySQL源碼中,binlog寫入的入口函數(shù)是binlog_log_row

// sql/binlog.cc
int binlog_log_row(TABLE *table, const uchar *before_record,
                   const uchar *after_record, Log_func *log_func) {
    THD *const thd = table->in_use;
    
    // 核心判斷:當前操作是否需要寫入binlog
    if (check_table_binlog_row_based(thd, table)) {
        // 寫入表映射信息
        if (!write_locked_table_maps(thd)) {
            // 根據(jù)操作類型調(diào)用不同的日志函數(shù)
            error = (*log_func)(thd, table, has_trans, 
                                before_record, after_record);
        }
    }
    return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
}

1.1 判斷邏輯流程圖

1.2 check_table_binlog_row_based源碼解析

static bool check_table_binlog_row_based(THD *thd, TABLE *table) {
    // 緩存判斷結(jié)果,避免重復(fù)計算
    if (table->s->cached_row_logging_check == -1) {
        int const check(
            table->s->tmp_table == NO_TMP_TABLE &&    // 不是臨時表
            !table->no_replicate &&                    // 允許復(fù)制
            binlog_filter->db_ok(table->s->db.str)     // 庫在復(fù)制白名單
        );
        table->s->cached_row_logging_check = check;
    }
    
    // 需要滿足4個條件才返回true
    return (thd->is_current_stmt_binlog_format_row() &&   // 行格式
            table->s->cached_row_logging_check &&          // 表允許復(fù)制
            (thd->variables.option_bits & OPTION_BIN_LOG) && // 線程啟用binlog
            mysql_bin_log.is_open());                        // binlog已打開
}

結(jié)論:只要上述4個條件任意一個不滿足,操作就不會寫入binlog。

2. 場景一:臨時表操作

2.1 現(xiàn)象演示

-- 創(chuàng)建臨時表
CREATE TEMPORARY TABLE temp_user (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

-- 插入數(shù)據(jù)(不會寫入binlog)
INSERT INTO temp_user VALUES (1, '張三');

-- 更新數(shù)據(jù)(不會寫入binlog)
UPDATE temp_user SET name = '李四' WHERE id = 1;

2.2 源碼驗證

// table->s->tmp_table == NO_TMP_TABLE 為false時,cached_row_logging_check為0
int const check(
    table->s->tmp_table == NO_TMP_TABLE &&  // 臨時表時,此條件為false
    !table->no_replicate &&
    binlog_filter->db_ok(table->s->db.str)
);

2.3 為什么臨時表不寫binlog?

根本原因:臨時表的生命周期僅限于創(chuàng)建它的會話,對其他會話(包括從庫)不可見,因此無需同步。

3. 場景二:特殊系統(tǒng)表

3.1 不寫binlog的系統(tǒng)表列表

表類別具體表名作用
日志表mysql.general_log通用查詢?nèi)罩?/td>
日志表mysql.slow_log慢查詢?nèi)罩?/td>
復(fù)制信息表mysql.slave_relay_log_info從庫中繼日志信息
復(fù)制信息表mysql.slave_master_info從庫主庫連接信息
復(fù)制信息表mysql.slave_worker_info從庫并行復(fù)制信息
GTID表mysql.gtid_executedGTID執(zhí)行記錄

3.2 現(xiàn)象演示

-- 開啟慢日志記錄到表
SET GLOBAL log_output = 'TABLE';
SET GLOBAL slow_query_log = ON;

-- 執(zhí)行慢查詢
SELECT SLEEP(2);

-- 查看慢日志表(寫入成功)
SELECT * FROM mysql.slow_log;

-- 但這些記錄不會同步到從庫!

3.3 源碼分析

// sql/table.cc - open_table_from_share函數(shù)
if ((share->table_category == TABLE_CATEGORY_LOG) ||
    (share->table_category == TABLE_CATEGORY_RPL_INFO) ||
    (share->table_category == TABLE_CATEGORY_GTID)) {
    outparam->no_replicate = true;  // 這些表設(shè)置no_replicate標志
}

表類別定義

// sql/table.h
enum enum_table_category {
  TABLE_CATEGORY_USER,      // 用戶表
  TABLE_CATEGORY_LOG,       // 日志表
  TABLE_CATEGORY_RPL_INFO,  // 復(fù)制信息表
  TABLE_CATEGORY_GTID,      // GTID表
  TABLE_CATEGORY_INFORMATION_SCHEMA,  // 信息模式
  TABLE_CATEGORY_PERFORMANCE_SCHEMA   // 性能模式
};

4. 場景三:Performance Schema表

4.1 現(xiàn)象演示

-- 嘗試修改performance_schema表(會報錯)
UPDATE performance_schema.accounts SET CURRENT_CONNECTIONS = 10;
-- ERROR: 1044 (42000): Access denied for user

-- 但可以truncate(不會寫入binlog)
TRUNCATE performance_schema.accounts;
-- Query OK, 0 rows affected

4.2 存儲引擎能力標志

// 在Perfschema存儲引擎的table_flags函數(shù)中
handler::Table_flags ha_perfschema::table_flags() const {
    return HA_REC_NOT_IN_SEQ | HA_NO_TRANSACTIONS | HA_NO_BINLOG;
    // HA_NO_BINLOG表示不支持binlog
}

判斷邏輯

else if (outparam->file) {
    const handler::Table_flags flags = outparam->file->ha_table_flags();
    outparam->no_replicate =
        !(flags & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) ||
        (flags & HA_HAS_OWN_BINLOGGING);
}

5. 場景四:顯式關(guān)閉binlog

5.1 會話級關(guān)閉

-- 關(guān)閉當前會話的binlog
SET SESSION sql_log_bin = 0;

-- 以下操作不會寫入binlog
INSERT INTO user VALUES (100, '測試用戶');
UPDATE user SET name = '新名字' WHERE id = 100;

-- 重新開啟
SET SESSION sql_log_bin = 1;

5.2 源碼回調(diào)函數(shù)

static bool fix_sql_log_bin_after_update(sys_var *, THD *thd,
                                         enum_var_type type) {
    if (thd->variables.sql_log_bin)
        thd->variables.option_bits |= OPTION_BIN_LOG;   // 開啟
    else
        thd->variables.option_bits &= ~OPTION_BIN_LOG;  // 關(guān)閉
    
    return false;
}

5.3 典型應(yīng)用場景

-- 場景1:批量導(dǎo)入大量數(shù)據(jù),避免binlog暴漲
SET SESSION sql_log_bin = 0;
LOAD DATA INFILE '/data/big_data.csv' INTO TABLE history_data;
SET SESSION sql_log_bin = 1;

-- 場景2:從庫配置不記錄重放日志
-- 在從庫上設(shè)置 log_replica_updates = OFF
-- 這樣從庫SQL線程重放的操作不寫入自己的binlog

6. 場景五:從庫未開啟log_replica_updates

6.1 配置說明

# my.cnf
[mysqld]
# MySQL 8.0之前
log_slave_updates = OFF

# MySQL 8.0+
log_replica_updates = OFF

6.2 源碼邏輯

void set_slave_thread_options(THD *thd) {
    ulonglong options = thd->variables.option_bits | OPTION_BIG_SELECTS;
    
    if (opt_log_replica_updates)
        options |= OPTION_BIN_LOG;      // 開啟:從庫操作記錄binlog
    else
        options &= ~OPTION_BIN_LOG;     // 關(guān)閉:從庫操作不記錄binlog
}

6. 場景六:臨時關(guān)閉binlog的代碼保護機制

6.1 Disable_binlog_guard類

MySQL在源碼中使用RAII機制臨時關(guān)閉binlog:

class Disable_binlog_guard {
public:
    explicit Disable_binlog_guard(THD *thd)
        : m_thd(thd),
          m_binlog_disabled(thd->variables.option_bits & OPTION_BIN_LOG) {
        // 構(gòu)造函數(shù)中關(guān)閉binlog
        thd->variables.option_bits &= ~OPTION_BIN_LOG;
    }
    
    ~Disable_binlog_guard() {
        // 析構(gòu)函數(shù)中恢復(fù)
        if (m_binlog_disabled)
            m_thd->variables.option_bits |= OPTION_BIN_LOG;
    }
    
private:
    THD *const m_thd;
    const bool m_binlog_disabled;
};

6.2 應(yīng)用場景

場景1:實例初始化(–initialize)

static bool handle_bootstrap_impl(handle_bootstrap_args *args) {
    if (opt_initialize) {
        const Disable_binlog_guard disable_binlog(thd);
        // 初始化系統(tǒng)表,這些操作不寫入binlog
        rc = process_iterator(thd, &comp_iter, true);
    }
}

場景2:實例升級

bool upgrade_system_schemas(THD *thd) {
    Disable_binlog_guard disable_binlog(thd);
    // 升級系統(tǒng)表,不寫入binlog
    err = fix_mysql_tables(thd) || fix_sys_schema(thd);
}

7. 場景七:NO_WRITE_TO_BINLOG關(guān)鍵字

7.1 支持的SQL命令

-- 1. OPTIMIZE TABLE
OPTIMIZE NO_WRITE_TO_BINLOG TABLE t1;
OPTIMIZE LOCAL TABLE t1;  -- LOCAL是NO_WRITE_TO_BINLOG的同義詞

-- 2. ANALYZE TABLE
ANALYZE NO_WRITE_TO_BINLOG TABLE t1;

-- 3. REPAIR TABLE
REPAIR NO_WRITE_TO_BINLOG TABLE t1;

-- 4. FLUSH命令
FLUSH NO_WRITE_TO_BINLOG PRIVILEGES;
FLUSH LOCAL TABLES;  -- LOCAL版本

7.2 源碼實現(xiàn)

// sql/sql_yacc.yy - 語法解析部分
opt_no_write_to_binlog:
    /* Empty */ { $$ = false; }
  | NO_WRITE_TO_BINLOG_SYM { $$ = true; }
  | LOCAL_SYM { $$ = true; }
  ;

// 在語法規(guī)則中設(shè)置
repair_table_stmt:
    REPAIR opt_no_write_to_binlog TABLE ...
    {
        Lex->sql_command = SQLCOM_REPAIR;
        Lex->no_write_to_binlog = $2;  // 設(shè)置no_write_to_binlog標志
    }

7.3 默認不寫binlog的FLUSH命令

-- 以下FLUSH命令即使不加NO_WRITE_TO_BINLOG,也不會寫入binlog
FLUSH LOGS;
FLUSH BINARY LOGS;
FLUSH TABLES WITH READ LOCK;
FLUSH TABLES tbl_name ... FOR EXPORT;

8. 場景八:performance_schema的TRUNCATE操作

8.1 現(xiàn)象

-- performance_schema表支持TRUNCATE
TRUNCATE performance_schema.events_statements_summary_by_digest;

-- 但不會寫入binlog
-- 從庫不會執(zhí)行這個TRUNCATE操作

8.2 原因分析

// storage/perfschema/ha_perfschema.cc
int ha_perfschema::truncate() {
    // 直接清空內(nèi)存數(shù)據(jù)結(jié)構(gòu)
    reset_table_handles(m_table);
    return 0;
    // 不調(diào)用binlog_log_row,不寫入binlog
}

9. 總結(jié)與對比表格

9.1 所有場景匯總

場景觸發(fā)條件判斷依據(jù)典型示例
臨時表操作臨時表tmp_table != NO_TMP_TABLECREATE TEMPORARY TABLE
系統(tǒng)日志表操作mysql.general_log等table_category == TABLE_CATEGORY_LOG慢日志寫入
復(fù)制信息表操作mysql.slave_*表table_category == TABLE_CATEGORY_RPL_INFO復(fù)制狀態(tài)更新
GTID表操作mysql.gtid_executedtable_category == TABLE_CATEGORY_GTIDGTID記錄
Performance Schema操作performance_schema表存儲引擎標志HA_NO_BINLOGTRUNCATE
會話級關(guān)閉SET sql_log_bin = 0OPTION_BIN_LOG標志批量導(dǎo)入
從庫不記錄log_replica_updates=OFFopt_log_replica_updates從鏈式復(fù)制
內(nèi)部操作實例初始化/升級Disable_binlog_guardmysqld --initialize
顯式指定NO_WRITE_TO_BINLOGlex->no_write_to_binlogOPTIMIZE LOCAL TABLE

9.2 快速判斷指南

10. 最佳實踐建議

10.1 日常開發(fā)注意事項

-- 1. 不要期望慢日志表被復(fù)制
-- ? 錯誤想法:在從庫查詢慢日志
SELECT * FROM mysql.slow_log;  -- 從庫可能是空的

-- ? 正確做法:在主庫查詢或通過監(jiān)控系統(tǒng)收集

-- 2. 批量操作記得關(guān)閉binlog
-- 大批量數(shù)據(jù)導(dǎo)入
SET SESSION sql_log_bin = 0;
-- 執(zhí)行批量操作
SET SESSION sql_log_bin = 1;

-- 3. 維護操作使用LOCAL關(guān)鍵字
OPTIMIZE LOCAL TABLE large_table;  -- 不寫binlog,減少網(wǎng)絡(luò)傳輸

10.2 復(fù)制環(huán)境配置建議

# 從庫配置:如果不是鏈式復(fù)制,建議關(guān)閉
[mysqld]
log_replica_updates = OFF
relay_log = relay-bin
read_only = ON

結(jié)語

通過源碼級別的分析,我們可以看到MySQL對binlog寫入有著精細的控制:

  • 內(nèi)部系統(tǒng)表:避免循環(huán)復(fù)制和性能開銷
  • 臨時對象:遵循會話隔離原則
  • 控制開關(guān):提供靈活的管理手段
  • RAII保護:確保關(guān)鍵操作的安全性

理解這些場景,不僅能幫助你更好地理解MySQL的運行機制,還能在實際運維中做出更合理的選擇。

以上就是從源碼到實戰(zhàn)盤點MySQL中不寫B(tài)inlog的N種場景的詳細內(nèi)容,更多關(guān)于MySQL不寫B(tài)inlog的場景的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 云服務(wù)器安裝mysql后如何設(shè)置示例詳解

    云服務(wù)器安裝mysql后如何設(shè)置示例詳解

    MySQL是一種廣泛使用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS),它允許開發(fā)者存儲、檢索和管理數(shù)據(jù),在云服務(wù)器上配置MySQL通常涉及安裝MySQL軟件、設(shè)置數(shù)據(jù)庫實例、配置網(wǎng)絡(luò)和安全設(shè)置等,這篇文章主要介紹了云服務(wù)器安裝mysql后如何設(shè)置的相關(guān)資料,需要的朋友可以參考下
    2025-10-10
  • Hibernate4在MySQL5.1以上版本創(chuàng)建表出錯 type=InnDB

    Hibernate4在MySQL5.1以上版本創(chuàng)建表出錯 type=InnDB

    本文主要介紹解決Hibernate4在MySQL5.1自動創(chuàng)建表出錯的方法,簡單實用,需要的朋友可以參考下。
    2016-05-05
  • MySQL下將一個表的數(shù)據(jù)插入到另外一個表的實現(xiàn)語句

    MySQL下將一個表的數(shù)據(jù)插入到另外一個表的實現(xiàn)語句

    開發(fā)中,我們經(jīng)常需要將一個表的數(shù)據(jù)插入到另外一個表,有時還需要指定導(dǎo)入字段,雖然這個實現(xiàn)起來非常簡單,但是還是會困擾許多新手,因此專門發(fā)一篇文章備查。
    2009-09-09
  • 詳解Centos7 修改mysql指定用戶的密碼

    詳解Centos7 修改mysql指定用戶的密碼

    本篇文章主要介紹了Centos7 修改mysql指定用戶的密碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧。
    2016-12-12
  • mysql 使用存儲過程實現(xiàn)樹節(jié)點的獲取方法

    mysql 使用存儲過程實現(xiàn)樹節(jié)點的獲取方法

    這篇文章主要介紹了mysql 使用存儲過程實現(xiàn)樹節(jié)點的獲取方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • 簡單了解添加mysql索引的3條原則

    簡單了解添加mysql索引的3條原則

    這篇文章主要介紹了簡單了解添加mysql索引的3條原則,如果表中查詢的列有一個索引,MySQL能快速到達一個位置去搜尋到數(shù)據(jù)文件的中間,沒有必要看所有數(shù)據(jù),需要的朋友可以參考下
    2019-06-06
  • window下mysql 8.0.15 winx64安裝配置方法圖文教程

    window下mysql 8.0.15 winx64安裝配置方法圖文教程

    這篇文章主要為大家詳細介紹了window下mysql 8.0.15 winx64安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 基于mysql時間處理函數(shù)的應(yīng)用詳解

    基于mysql時間處理函數(shù)的應(yīng)用詳解

    本篇文章是對mysql時間處理函數(shù)進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • MySql中的常用參數(shù)查詢

    MySql中的常用參數(shù)查詢

    這篇文章主要介紹了MySql中的常用參數(shù)查詢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Windows下MySQL?8.0.29?安裝和刪除圖文教程

    Windows下MySQL?8.0.29?安裝和刪除圖文教程

    這篇文章主要為大家詳細介紹了Windows下MySQL?8.0.29?安裝和刪除圖文教程,文中安裝步驟介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07

最新評論

河北省| 东乌| 历史| 娄烦县| 哈尔滨市| 密云县| 买车| 九台市| 永吉县| 固原市| 准格尔旗| 门头沟区| 云林县| 嘉义县| 海口市| 和田市| 阳西县| 海门市| 海林市| 姜堰市| 乡宁县| 海口市| 南平市| 呼玛县| 常州市| 璧山县| 咸宁市| 合肥市| 南华县| 平武县| 新巴尔虎右旗| 疏勒县| 石渠县| 十堰市| 舟曲县| 钦州市| 区。| 长子县| 南陵县| 商河县| 应用必备|