type
status
date
slug
summary
tags
category
icon
password

前言

一次意外中發現 source 和 replica 在其中一張表中的某一個欄位有不同名稱(資料型態相同):
大概如上範例所示,但是 replication 卻沒有中斷,而且也沒有遺漏資料的狀況,因此對原因感到好奇,在查看官方文檔加上實際測試發現和文檔上的說明有出入,因此以此筆記記錄下來。
備註:本文基於 MySQL 8.0.21 版本與 MySQL 8.0 文檔撰寫。

Replication with Differing Table Definitions on Source and Replica

運行 replication 時 Source 和 Replica 上的 table schema 不需要完全相同,例如:source 比 replica 具有較多或較少的欄位、source 和 replica 欄位可以有不同的資料型態,當然這會受到一些限制。
官方文檔:
partition 定義不同的表無法進行 replication,這是因為直接作用於 partition 的語句(例如:ALTER TABLE ... DROP PARTITION)可能導致 source 和 replica 有不同的結果。

實測:
partition 定義不同在一般的 DML 不會出錯,但像上述的 ALTER 例子確實會有問題,所以不建議 replication 中使用不同的 partition 定義。
官方文檔: partition 定義不同的表無法進行 replication,這是因為直接作用於 partition 的語句(例如:ALTER TABLE ... DROP PARTITION)可能導致 source 和 replica 有不同的結果。 實測: partition 定義不同在一般的 DML 不會出錯,但像上述的 ALTER 例子確實會有問題,所以不建議 replication 中使用不同的 partition 定義。

Statement-based replication

當 binlog format = Statement 時,只需要記住:在 source 執行的 SQL 語法若也能在 replica 上正確運行,那麼就能夠正確的運行 replication。
例如:我們可以將 tinyint 允許的值插入到 bigint 型態的欄位,因此如果在 source 中有 tinyint 的欄位其對應到 replica 中屬於 bigint 型態也可以正確的運行 replication。

範例

以下例子中兩者 c1 欄位都是整數型態,但是 replica 的 c1 欄位閾值較大,此情況下 replication 不會因錯誤中斷,也不會產生數值截斷的問題:
以下例子中兩者 c1 欄位都是整數型態,但是 replica 的 c1 欄位閾值較小,此情況下 replication 不會因錯誤中斷,但是當 source 在 c1 插入大於 127 的值,到 replica 的 c1 就會被截斷成 127:
以下例子中 source 比 replica 多了一個 c3 欄位,因此當在 source 執行的語法有出現 c3 欄位時就會引發 replcation 中斷的問題;反之當 source 執行的語法沒有出現 c3 欄位則不會引發錯誤:

Row-based replication

Source 或 Replica 欄位數量不一致

在 Source 和 Replica 可以在具有不同欄位數量時,仍然可以運行 Replication,需要符合以下條件:
  • Source 和 Replica 兩者都有的欄位(此處指的不是欄位名稱,而是欄位上的資料型態)需要以相同的順序定義,即使兩者欄位數量一致也需要符合此規範。
  • 多餘的欄位必須要定義在兩者都有的欄位之後。
  • 多餘的欄位必須具有默認值。經過實測並不需要具有默認值。

範例

在以下範例中 source 多了一個欄位,但可以正常進行 Replication:
以下範例中兩者都有的欄位 (c1,c2) 以不同的順序定義,因此 replication 會引發錯誤:
以下範例中兩者都有的欄位 (c1,c2) 定義在多餘的 c3 欄位之後,因此 replication 會引發錯誤:
以下範例中 replica 多了 c3 欄位,但兩者共有的欄位 (c1,c2) 具有相同的 data type 且定義順序一致, 因此 replication 不會引發錯誤:
以下範例中 replica 多了 c3 欄位,但兩者共有的欄位 (INT,varchar) 以相同的順序定義,儘管欄位名稱不同, 但 replication 不會引發錯誤:
在上一個案例中我們可以看到文檔中提到的:兩者都有的欄位要以相同的順序定義。其實指的不是欄位名稱相同而是欄位型態,原因其實我們看一下 binlog 的內容就知道了:
因為在 row 格式的 binlog 內,是沒有紀錄欄位名稱的,而是只有順序資料型態

Source 和 Replica 欄位型態不一致

對於 Source 和 Replica 之間相應的欄位在理想的情況下應該具有相同的資料型態,不過只要 replica 和 source 具有相同類型和相同大小(或更大) 的資料型態也是可以進行 replication。
例如:可以從 char(10) 欄位 replication 到另一個 char(10) 欄位,或是從 char(10) 欄位 replication 到 char(25) 欄位而不會出現問題。
上述情境從 source 欄位 replication 到具有不同資料型態的 replica 欄位,並且是具有相同大小或更大的類型時,這稱為 attribute promotion。
Whether you use statement-based or row-based replication, the replica's copy of the table cannot contain more columns than the source's copy if you wish to employ attribute promotion.
官方文檔中說明當使用 attribute promotion 時,replica 不能比 source 有更多的欄位,但是經過實作確認是可以的,如下範例是可以同步成功的:
source> CREATE TABLE t1 (c1 INT, c2 varchar(5));
replica>    CREATE TABLE t1 (c3 INT, c2 varchar(5), c4 timestamp);
Whether you use statement-based or row-based replication, the replica's copy of the table cannot contain more columns than the source's copy if you wish to employ attribute promotion. 官方文檔中說明當使用 attribute promotion 時,replica 不能比 source 有更多的欄位,但是經過實作確認是可以的,如下範例是可以同步成功的: source> CREATE TABLE t1 (c1 INT, c2 varchar(5)); replica> CREATE TABLE t1 (c3 INT, c2 varchar(5), c4 timestamp);
當 binlog_format = row 的情況下是支援 attribute promotion 和 demotion 的,也就是除了可以從 source 小型態到 replica 大型態以外,還可以指定是否允許從 source 大型態到 replica 小型態的有損轉換。

轉換模式的設定

關於資料型態的的轉換模式,可以透過 slave_type_conversions 進行控制,提供以下選項:
slave_type_conversions 設定
效果
[empty]
此為預設值,不允許任何 attribute promotion 和 demotion,也就是說欄位在 source 和 replica 必須要是同一個型態。
ALL_LOSSY
此模式允許有損轉換,也就是說允許在 replica 中比 source 具有更小取值範圍的型態,例如:source(int) 到 replica (tinyint) 的情境。
ALL_NON_LOSSY
此模式允許對於 source 值不需要截斷或其他特殊處理的轉換,也就是說允許在 replica 中比 source 具有更大取值範圍的型態,例如:source (tinyint) 到 replica(int) 的情境。
ALL_LOSSY,ALL_NON_LOSSY
此模式同時允許有損、無損轉換。
ALL_SIGNED
當發生 attribute promotion 時,將提升的整數型態視為 signed (預設行為)。
ALL_UNSIGNED
當發生 attribute promotion 時,將提升的整數型態視為 unsigned。
ALL_SIGNED,ALL_UNSIGNED
當發生 attribute promotion 時,如果可以則視為 signed,否則視為 unsigned。
備註:若沒有設置 ALL_LOSSY,ALL_NON_LOSSY 則 ALL_SIGNED 和 ALL_UNSIGNED 不會有作用。

型態轉換

以下列出支持互相轉換的型態,不在下述列表中的型態不予進行轉換:
data type 類型
型態
備註
integer型態
TINYINT, SMALLINT, MEDIUMINT, INT, and BIGINT.
有損轉換的情況下,會透過將 source 值轉換成 replica 型態的最大最小值來達到。
decimal 型態
DECIMAL,FLOAT,DOUBLE and NUMERIC.
DECIMAL、NUMERIC 會根據四捨五入轉換 ; FLOAT,DOUBLE 則會參照 C library 的行為。
string 型態
CHAR,VARCHAR and TEXT.
有損轉換的情況下,會截斷超出範圍的字符。 此外不支持不同字符集的 replication。
binary 型態
BINARY,VARBINARY and BLOB
有損轉換的情況下,會截斷超出範圍的字符。
2 bit 型態
任何只有 2 種值的 2bit 型態

懶人包整理

binlog_format = statement

只要在 Source 運行的 Query 可以在 Replica 執行,就不會中斷 Replication。

binlog_format = row

  1. 不管是 Source 還是 Replica 多餘的欄位都必須要定義在兩者都有的欄位後面
  1. 上述的 Source 和 Replica 兩者都有的欄位,指的不是欄位名稱,而是需要以相同的順序定義相同的資料型態,即使兩者欄位數量一致也需要符合此規範。
  1. 呈上則,根據 slave_type_conversions 的設定可以允許 Source 和 Replica 上的欄位有資料型態的不同,具體可允許的程度請參考轉換模式的設定型態轉換章節。

參考