透過實測驗證 MySQL 主從架構中,四種程式物件 (Stored Procedure, Function, Trigger, Event) 的 Binlog 記錄與複製機制差異,釐清常見誤區。
CREATE TABLE test.t1 (name VARCHAR(10), age INT);
DELIMITER //
CREATE PROCEDURE p1 (IN name VARCHAR(10), IN age INT)
BEGIN
INSERT INTO test.t1 VALUES (name, age);
END//
DELIMITER ;
Binlog 記錄 CREATE PROCEDURE DDL 語句。
CALL p1('tom', 10);
關鍵發現: Binlog 記錄的是過程內部的 實際 DML 語句 (INSERT INTO test.t1 VALUES(...)),而非 CALL p1(...) 呼叫動作本身。從庫重放的是具體資料異動。
CREATE FUNCTION f1 (string VARCHAR(5)) RETURNS VARCHAR(20) DETERMINISTIC
RETURN CONCAT('f1', string);
Binlog 記錄 CREATE FUNCTION DDL。
INSERT INTO t1(name) VALUES(f1('steve'));
Binlog 記錄 原始呼叫語句,從庫同樣執行函數計算。
# Binlog 內容
INSERT INTO `test`.`t1` SET @1='f1steve', @2=NULL;
Binlog 記錄 函數計算後的結果值,從庫不執行函數,直接寫入結果。此模式下從庫不需存在函數定義也能複製成功。
CREATE TRIGGER t_test1 BEFORE INSERT ON test1
FOR EACH ROW
BEGIN
INSERT INTO test2 SET a2 = NEW.a1;
END;
INSERT INTO test1 VALUES(1); -- 觸發器自動插入 test2
關鍵發現: Binlog 僅記錄 觸發條件語句 (INSERT INTO test1 VALUES(1)),不記錄觸發器內部動作。主從雙方各自執行觸發器邏輯,需確保從庫存在相同觸發器定義。
CREATE EVENT e_test1 ON SCHEDULE EVERY 10 SECOND
DO INSERT INTO test.test1 VALUES (UNIX_TIMESTAMP());
SET GLOBAL event_scheduler = ON;
INSERT INTO test.test1 VALUES (1476155165))SHOW EVENTS 顯示狀態為 SLAVESIDE_DISABLEDevent_scheduler=ON 也不會重複執行,避免主從雙寫衝突| 物件類型 | Binlog 記錄內容 | 從庫執行行為 | 注意事項 |
|---|---|---|---|
| 存儲過程 | 內部 DML 語句 | 重放 DML | 從庫需有過程定義才能建立,但複製時重放的是 DML |
| 函數 (STATEMENT) | 函數呼叫語句 | 執行函數計算 | 從庫必須存在相同函數定義 |
| 函數 (ROW) | 計算後結果值 | 直接寫入結果 | 從庫無需函數定義,效能較好 |
| 觸發器 | 觸發條件 DML | 各自執行觸發邏輯 | 主從必須同步建立觸發器 |
| 事件 | 事件內部 DML | 重放 DML,不執行排程 | 從庫事件狀態為 SLAVESIDE_DISABLED |
binlog_format=ROW 減少函數/觸發器相容性問題SHOW SLAVE STATUS 確認複製無延遲