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 定義。
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。
當 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
- 不管是 Source 還是 Replica 多餘的欄位都必須要定義在兩者都有的欄位後面。
- 上述的 Source 和 Replica 兩者都有的欄位,指的不是欄位名稱,而是需要以相同的順序定義相同的資料型態,即使兩者欄位數量一致也需要符合此規範。