本節提供預存函數的範例 (請參閱第 27 章,預存物件),您可以使用 MySQL 提供的一些內建函數來建立這些預存函數,以便與基於 GTID 的複寫搭配使用,這些函數在此列出
GTID_SUBSET():顯示一個 GTID 集合是否為另一個集合的子集。GTID_SUBTRACT():傳回一個 GTID 集合中不在另一個集合中的 GTID。WAIT_FOR_EXECUTED_GTID_SET():等待直到已執行給定 GTID 集合中的所有交易。
請參閱第 14.18.2 節,"用於全域交易識別碼 (GTID) 的函數",以取得有關剛才列出的函數的更多資訊。
請注意,在這些預存函數中,delimiter 命令已用於將 MySQL 陳述式分隔符號變更為垂直線,如下所示
mysql> delimiter |本節中顯示的所有預存函數都採用 GTID 集合的字串表示形式作為引數,因此在使用時必須始終引用 GTID 集合。
如果兩個 GTID 集合相同,即使它們的格式不同,此函數也會傳回非零值 (true)
CREATE FUNCTION GTID_IS_EQUAL(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS INT
RETURN GTID_SUBSET(gs1, gs2) AND GTID_SUBSET(gs2, gs1)
|如果兩個 GTID 集合不相交,此函數會傳回非零值 (true)
CREATE FUNCTION GTID_IS_DISJOINT(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS INT
RETURN GTID_SUBSET(gs1, GTID_SUBTRACT(gs1, gs2))
|如果兩個 GTID 集合不相交且 sum 是它們的聯集,此函數會傳回非零值 (true)
CREATE FUNCTION GTID_IS_DISJOINT_UNION(gs1 LONGTEXT, gs2 LONGTEXT, sum LONGTEXT)
RETURNS INT
RETURN GTID_IS_EQUAL(GTID_SUBTRACT(sum, gs1), gs2) AND
GTID_IS_EQUAL(GTID_SUBTRACT(sum, gs2), gs1)
|此函數傳回 GTID 集合的正規化形式,全部大寫,沒有空格且沒有重複項,UUID 按字母順序排列,間隔按數字順序排列
CREATE FUNCTION GTID_NORMALIZE(gs LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs, '')
|
此函數傳回兩個 GTID 集合的聯集
CREATE FUNCTION GTID_UNION(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_NORMALIZE(CONCAT(gs1, ',', gs2))
|此函數傳回兩個 GTID 集合的交集。
CREATE FUNCTION GTID_INTERSECTION(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs1, GTID_SUBTRACT(gs1, gs2))
|此函數傳回兩個 GTID 集合之間的對稱差,也就是說,存在於 gs1 但不存在於 gs2 中的 GTID,以及存在於 gs2 但不存在於 gs1 中的 GTID。
CREATE FUNCTION GTID_SYMMETRIC_DIFFERENCE(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(CONCAT(gs1, ',', gs2), GTID_INTERSECTION(gs1, gs2))
|此函式會從 GTID 集合中移除所有具有指定來源的 GTID,並傳回剩餘的 GTID (如果有的話)。UUID 是交易來源伺服器使用的識別符,通常是 server_uuid 的值。
CREATE FUNCTION GTID_SUBTRACT_UUID(gs LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs, CONCAT(UUID, ':1-', (1 << 63) - 2))
|此函式的作用與前一個函式相反;它只會從 GTID 集合中傳回那些來源自具有指定識別符 (UUID) 的伺服器的 GTID。
CREATE FUNCTION GTID_INTERSECTION_WITH_UUID(gs LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs, GTID_SUBTRACT_UUID(gs, uuid))
|
範例 19.1:驗證複本是否為最新狀態
內建函式 GTID_SUBSET() 和 GTID_SUBTRACT() 可用於檢查複本是否至少套用了來源已套用的每筆交易。
若要使用 GTID_SUBSET() 執行此檢查,請在複本上執行下列陳述式
SELECT GTID_SUBSET(source_gtid_executed, replica_gtid_executed);如果傳回值為 0 (false),則表示 source_gtid_executed 中的某些 GTID 不存在於 replica_gtid_executed 中,且複本尚未套用來源上已套用的交易,這表示複本不是最新狀態。
若要使用 GTID_SUBTRACT() 執行相同的檢查,請在複本上執行下列陳述式
SELECT GTID_SUBTRACT(source_gtid_executed, replica_gtid_executed);此陳述式會傳回 source_gtid_executed 中但不在 replica_gtid_executed 中的任何 GTID。如果傳回任何 GTID,則表示來源已套用複本尚未套用的某些交易,因此複本不是最新狀態。
範例 19.2:備份和還原情境
儲存函式 GTID_IS_EQUAL()、GTID_IS_DISJOINT() 和 GTID_IS_DISJOINT_UNION() 可用於驗證涉及多個資料庫和伺服器的備份和還原操作。在此範例情境中,server1 包含資料庫 db1,而 server2 包含資料庫 db2。目標是將資料庫 db2 複製到 server1,而 server1 上的結果應為兩個資料庫的聯集。使用的程序是使用 mysqldump 備份 server2,然後在 server1 上還原此備份。
假設執行 mysqldump 時,--set-gtid-purged 設定為 ON 或 AUTO (預設值),則輸出包含 SET @@GLOBAL.gtid_purged 陳述式,該陳述式會將 server2 的 gtid_executed 集合新增至 server1 的 gtid_purged 集合。gtid_purged 包含在給定伺服器上已提交,但在伺服器上的任何二進位日誌檔案中都不存在的交易的 GTID。當資料庫 db2 複製到 server1 時,server2 上提交的交易的 GTID (不在 server1 上的二進位日誌檔案中) 必須新增至 server1 的 gtid_purged,以使集合完整。
儲存函式可用於協助此情境中的下列步驟
使用
GTID_IS_EQUAL()來驗證備份操作是否為SET @@GLOBAL.gtid_purged陳述式計算了正確的 GTID 集合。在server2上,從 mysqldump 輸出中擷取該陳述式,並將 GTID 集合儲存到本機變數中,例如$gtid_purged_set。然後執行下列陳述式server2> SELECT GTID_IS_EQUAL($gtid_purged_set, @@GLOBAL.gtid_executed);如果結果為 1,則表示兩個 GTID 集合相等,且已正確計算該集合。
使用
GTID_IS_DISJOINT()來驗證 mysqldump 輸出中的 GTID 集合與server1上的gtid_executed集合不重疊。在將資料庫db2複製到server1時,兩個伺服器上存在相同的 GTID 會導致錯誤。若要檢查,請在server1上,擷取並將輸出中的gtid_purged儲存到本機變數中,如先前所述,然後執行下列陳述式server1> SELECT GTID_IS_DISJOINT($gtid_purged_set, @@GLOBAL.gtid_executed);如果結果為 1,則表示兩個 GTID 集合之間沒有重疊,因此不存在重複的 GTID。
使用
GTID_IS_DISJOINT_UNION()來驗證還原操作是否在server1上產生了正確的 GTID 狀態。在還原備份之前,請在server1上,執行下列陳述式取得現有的gtid_executed集合server1> SELECT @@GLOBAL.gtid_executed;將結果儲存到本機變數
$original_gtid_executed中,並將gtid_purged中的集合儲存到另一個本機變數中,如先前所述。當server2的備份還原到server1上時,請執行下列陳述式以驗證 GTID 狀態server1> SELECT -> GTID_IS_DISJOINT_UNION($original_gtid_executed, -> $gtid_purged_set, -> @@GLOBAL.gtid_executed);如果結果為
1,則表示儲存函式已驗證來自server1的原始gtid_executed集合 ($original_gtid_executed) 和從server2新增的gtid_purged集合 ($gtid_purged_set) 沒有重疊,且server1上更新的gtid_executed集合現在由來自server1的先前gtid_executed集合加上來自server2的gtid_purged集合組成,這是想要的結果。請確保在server1上發生任何進一步交易之前執行此檢查,否則gtid_executed中的新交易會導致其失敗。
範例 19.3:選取最新狀態的複本以進行手動容錯移轉
儲存函式 GTID_UNION() 可用於從一組複本中識別最新狀態的複本,以便在來源伺服器意外停止後執行手動容錯移轉操作。如果某些複本遇到複寫延遲,則可以使用此儲存函式來計算最新狀態的複本,而無需等待所有複本套用其現有的中繼日誌,從而縮短容錯移轉時間。此函式可以傳回每個複本上的 gtid_executed 與複本接收的交易集合的聯集,該交易集合記錄在效能結構描述 replication_connection_status 資料表中。您可以比較這些結果,以找出哪個複本的交易記錄為最新狀態,即使並非所有交易都已提交。
在每個複本上,透過發出下列陳述式來計算完整的交易記錄
SELECT GTID_UNION(RECEIVED_TRANSACTION_SET, @@GLOBAL.gtid_executed)
FROM performance_schema.replication_connection_status
WHERE channel_name = 'name';然後,您可以比較每個複本的結果,以查看哪個複本具有最新狀態的交易記錄,並使用此複本作為新的來源。
範例 19.4:檢查複本上是否存在多餘的交易
儲存函式 GTID_SUBTRACT_UUID() 可用於檢查複本是否接收了並非來自其指定來源或來源的交易。如果是,則您的複寫設定或 Proxy、路由器或負載平衡器可能存在問題。此函式的作用是從 GTID 集合中移除來自指定來源伺服器的所有 GTID,並傳回剩餘的 GTID (如果有的話)。
對於具有單一來源的複本,請發出下列陳述式,並提供來源的識別符,該識別符通常與 server_uuid 相同
SELECT GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed, server_uuid_of_source);如果結果不是空的,則傳回的交易是並非來自指定來源的多餘交易。
對於多來源拓撲中的複本,請在函式呼叫中包含每個來源的伺服器 UUID,如下所示
SELECT
GTID_SUBTRACT_UUID(GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed,
server_uuid_of_source_1),
server_uuid_of_source_2);如果結果不是空的,則傳回的交易是並非來自任何指定來源的多餘交易。
範例 19.5:驗證複寫拓撲中的伺服器是否為唯讀
儲存函式 GTID_INTERSECTION_WITH_UUID() 可用於驗證伺服器是否未產生任何 GTID 且處於唯讀狀態。此函式只會從 GTID 集合中傳回那些來源自具有指定識別符的伺服器的 GTID。如果此伺服器上的 gtid_executed 中列出的任何交易使用伺服器自己的識別符,則表示伺服器本身產生了這些交易。您可以在伺服器上發出下列陳述式進行檢查
SELECT GTID_INTERSECTION_WITH_UUID(@@GLOBAL.gtid_executed, my_server_uuid);
範例 19.6:驗證多來源複寫中的額外複本
儲存函式 GTID_INTERSECTION_WITH_UUID() 可用於找出附加至多來源複寫設定的複本是否已套用來自特定來源的所有交易。在此情境中,source1 和 source2 都是來源和複本,並且彼此複寫。source2 也有自己的複本。如果 source2 設定為 log_replica_updates=ON,則複本也會接收並套用來自 source1 的交易,但如果 source2 使用 log_replica_updates=OFF,則不會。無論哪種情況,我們目前只想找出複本是否為 source2 的最新狀態。在此情況下,GTID_INTERSECTION_WITH_UUID() 可用於識別 source2 產生的交易,並捨棄 source2 從 source1 複寫的交易。然後,可以使用內建函式 GTID_SUBSET() 將結果與複本上的 gtid_executed 集合進行比較。如果複本為 source2 的最新狀態,則複本上的 gtid_executed 集合會包含交集集合中的所有交易 (來源自 source2 的交易)。
若要執行此檢查,請將 source2 的 gtid_executed 值和伺服器 UUID 以及複本的 gtid_executed 值儲存到使用者變數中,如下所示
source2> SELECT @@GLOBAL.gtid_executed INTO @source2_gtid_executed;
source2> SELECT @@GLOBAL.server_uuid INTO @source2_server_uuid;
replica> SELECT @@GLOBAL.gtid_executed INTO @replica_gtid_executed;然後,使用 GTID_INTERSECTION_WITH_UUID() 和 GTID_SUBSET(),並將這些變數作為輸入,如下所示
SELECT
GTID_SUBSET(
GTID_INTERSECTION_WITH_UUID(@source2_gtid_executed,
@source2_server_uuid),
@replica_gtid_executed);來自 source2 的伺服器識別符 (@source2_server_uuid) 與 GTID_INTERSECTION_WITH_UUID() 一起使用,以識別並僅傳回來源自 source2 的 GTID 集合中的那些 GTID,並省略來源自 source1 的 GTID。然後,使用 GTID_SUBSET() 將產生的 GTID 集合與複本上所有已執行 GTID 的集合進行比較。如果此陳述式傳回非零 (true),則表示來自 source2 的所有已識別 GTID (第一個集合輸入) 也會在複本的 gtid_executed 中找到,這表示複本已接收並執行了所有來源自 source2 的交易。