本文說明如何將線上交易處理 (OLTP) 資料庫從 MySQL 遷移到 Spanner。
遷移限制條件
Spanner 使用的一些概念與其他企業資料庫管理工具不同,您可能需要調整應用程式架構,以充分利用其功能。您可能也需要以Google Cloud 的其他服務補足 Spanner,以滿足您的需求。
內儲程序和觸發條件
Spanner 不支援在資料庫層級執行使用者程式碼,因此在遷移時,必須將資料庫層級的內儲程序和觸發條件實作的企業邏輯一起遷移到應用程式內。
序列
Spanner 建議您使用 UUID 第 4 版做為產生主鍵值的預設方法。GENERATE_UUID()
函式 (GoogleSQL、PostgreSQL) 會傳回以 STRING
型別表示的 UUID 4 版值。
如果您需要產生整數值,Spanner 支援位元反轉的正向序列 (GoogleSQL、PostgreSQL),可產生在正向 64 位元數字空間中平均分配的值。您可以使用這些數字避免出現資源使用率不均的問題。
詳情請參閱「主鍵預設值策略」。
存取權控管
Spanner 支援資料表和資料欄層級的精細存取權控管機制。系統不支援精細的檢視區塊存取權控管機制。詳情請參閱「關於精細的存取權控管機制」。
資料驗證限制條件
Spanner 在資料庫層支援有限的一套資料驗證限制條件。如果您需要更複雜的資料限制條件,則必須在應用程式層實作。
下表討論在 MySQL 資料庫中常見的限制條件類型,以及如何使用 Spanner 進行實作。
限制 | 使用 Spanner 實作 |
---|---|
Not null | NOT NULL 欄限制條件 |
唯一限制 | 具有 UNIQUE 限制條件的次要索引 |
Foreign key (適用於普通資料表) |
請參閱「建立及管理外來鍵關係」。 |
外鍵 ON DELETE/ON UPDATE 動作 |
僅適用於交錯式資料表,否則在應用程式層實施。 |
透過 CHECK 限制條件進行值的檢查和驗證 |
請參閱「建立及管理檢查限制」。 |
透過觸發事件進行值的檢查和驗證 | 在應用程式層實施 |
產生的資料欄
Spanner 支援產生的資料欄,資料欄值一律會由表格定義中提供的函式產生。與 MySQL 一樣,產生的資料欄無法在 DML 陳述式中明確設為提供的值。
系統會在 CREATE TABLE
或 ALTER TABLE
資料定義語言 (DDL) 陳述式中,將產生的資料欄定義為資料欄定義的一部分。AS
關鍵字後面會接著有效的 SQL 函式和必要的後置關鍵字 STORED
。STORED
關鍵字是 ANSI SQL 規範的一部分,表示函式結果會與資料表的其他欄一起儲存。
SQL 函式 (產生運算式) 可包含任何確定性的運算式、函式和運算子,並可用於次要索引或做為外鍵。
如要進一步瞭解如何管理這類欄,請參閱建立及管理產生的欄。
支援的資料類型
MySQL 和 Spanner 支援不同的資料類型。下表列舉了 MySQL 資料類型和 Spanner 中與其對等的資料類型。如要進一步瞭解各 Spanner 資料類型的詳細定義,請參閱「資料類型」。
您可能也必須按照「Note」(附註) 欄的描述對資料進行進一步的轉換,讓 MySQL 資料符合您的 Spanner 資料庫。例如,您可以將大型 BLOB
儲存為 Cloud Storage 值區中的物件,而非儲存於資料庫中,將 URI 參考以 STRING
形式儲存至資料庫中的 Cloud Storage 物件。
MySQL 資料類型 | Spanner 等價 | 附註 |
---|---|---|
INTEGER 、INT 、BIGINT MEDIUMINT 、SMALLINT |
INT64 |
|
TINYINT 、BOOL 、BOOLEAN |
BOOL 、INT64 |
TINYINT(1) 值用於表示「true」(非零) 或「false」(0) 的布林值。 |
FLOAT 、DOUBLE |
FLOAT64 |
|
DECIMAL 、NUMERIC |
NUMERIC 、STRING
|
在 MySQL 中,NUMERIC 和 DECIMAL 資料類型最多支援 65 位有效位數和小數位數,如欄宣告中所定義。Spanner NUMERIC 資料類型最多支援 38 位精確度和 9 位小數位數。如需更高精確度,請參閱「儲存任意精確度數值資料」一文,瞭解替代機制。 |
BIT |
BYTES |
|
DATE |
DATE |
Spanner 和 MySQL 都使用「yyyy-mm-dd 」日期格式,因此不需要進行轉換。提供 SQL 函式,將日期轉換為格式化字串。 |
DATETIME 、TIMESTAMP |
TIMESTAMP |
Spanner 儲存與時區無關的時間。因此您必須儲存時區,則必須使用單獨的 STRING 列。提供 SQL 函式,使用時區將時間戳記轉換為格式化字串。 |
CHAR 、VARCHAR |
STRING |
注意:Spanner 一律使用 Unicode 字串。 VARCHAR 支援的最大長度為 65,535 個位元組,Spanner 則最多支援 2,621,440 個字元。 |
BINARY 、VARBINARY 、BLOB 、TINYBLOB |
BYTES |
小型物件 (小於 10 MiB) 可儲存為 BYTES 。請考慮使用其他 Google Cloud 產品 (例如 Cloud Storage) 來儲存較大型的物件 |
TEXT 、TINYTEXT 、ENUM |
STRING
|
小型 TEXT 值 (小於 10 MiB) 可儲存為 STRING 。請考慮使用其他 Google Cloud 產品 (例如 Cloud Storage) 來支援較大的 TEXT 值。 |
ENUM |
STRING |
ENUM 值的驗證必須在應用程式中執行。 |
SET |
ARRAY<STRING> |
SET 元件中值的驗證必須在應用程式中執行。 |
LONGBLOB 、MEDIUMBLOB |
包含物件 URI 的 BYTES 或 STRING 。 |
小型物件 (小於 10 MiB) 可儲存為 BYTES 。請考慮使用其他 Google Cloud 產品 (例如 Cloud Storage) 來儲存較大型的物件。 |
LONGTEXT 、MEDIUMTEXT |
STRING (包含資料或指向外部物件的 URI) |
小型物件 (小於 2,621,440 個字元) 可儲存為 STRING 。請考慮使用其他 Google Cloud 產品 (例如 Cloud Storage) 來儲存較大型的物件 |
JSON |
JSON
|
小型 JSON 字串 (少於 2,621,440 個字元) 可儲存為 JSON 。請考慮使用其他 Google Cloud 產品 (例如 Cloud Storage) 來儲存較大型的物件。 |
GEOMETRY ,POINT ,LINESTRING ,POLYGON ,MULTIPOINT ,MULTIPOLYGON ,GEOMETRYCOLLECTION |
Spanner 不支援地理空間資料類型。您必須使用標準資料類型儲存此資料,並在應用程序層中實作任何搜尋和過濾邏輯。 |
遷移流程
遷移過程的時間表如下:
- 轉換結構定義和資料模型。
- 翻譯任何 SQL 查詢。
- 遷移應用程式,除了 MySQL 之外,還會使用 Spanner。
- 使用 Dataflow 從 MySQL 大量匯出資料,並將資料匯入 Spanner。
- 在遷移期間維持兩個資料庫之間的一致性。
- 將應用程式從 MySQL 遷移出去。
步驟 1:轉換資料庫和結構定義
您將現有的結構定義轉換成 Spanner 結構定義,以儲存您的資料。為了簡化應用程式修改,請確保轉換的結構定義能盡量與 MySQL 結構定義相符。然而,由於功能的差異,您必須做一些變更。
使用結構定義設計的最佳做法可協助您增加總處理量,並減少 Spanner 資料庫中的熱點。
主要金鑰
在 Spanner 中,每個需要儲存一列以上的資料表都必須具有由該資料表的一欄或多欄組成的主鍵。您的資料表的主鍵將唯一識別資料表中的每一列,Spanner 會使用主鍵排序資料表資料列。由於 Spanner 是高度分散式資料庫,因此請務必選擇可隨著資料成長而擴充的主要索引鍵產生技術。詳情請參閱我們建議的主鍵遷移策略。
請注意,指定主鍵後,除非刪除並重新建立資料表,否則無法新增或移除主鍵資料欄,也無法變更主鍵值。如要進一步瞭解如何指定主鍵,請參閱「結構定義和資料模型 - 主鍵」。
交錯資料表
Spanner 有一個功能,可將兩份資料表定義為具有一對多的父項─子項關係。這會讓子項資料列與其父項列在儲存空間中交錯,實際上是將資料表預先彙整,當父項與子項一起被查詢時,可以改善資料擷取效率。
子項資料表的主鍵必須從父項資料表的主鍵欄開始。從子項列的觀點來看,父項列主鍵被稱為外部鍵。您最多可以定義六層的父項─子項關係。
您可以為子項資料表定義 on-delete 動作,以決定當父項列被刪除時,會發生什麼事:所有子項列都被刪除,或當子項列存在時,父項列刪除會被封鎖。
以下是建立交錯於先前定義的父項 Singers 資料表中 Albums 資料表的範例:
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId)
INTERLEAVE IN PARENT (Singers)
ON DELETE CASCADE;
建立次要索引
您也可以建立次要索引,從主鍵之外索引資料表內的資料。Spanner 使用和資料表相同的方式實作次要索引,讓欲使用為索引鍵的欄值具有和資料表主鍵相同的限制條件。這也表示索引具有和 Spanner 一樣的一致性保證。
使用次要索引進行值查詢實際上等於使用資料表彙整的查詢。您可以使用 STORING
子句,將原始資料表的欄值副本儲存於次要索引,使其成為覆蓋索引,以改善查詢效能。
當索引本身儲存了被查詢的所有欄 (覆蓋查詢) 時,Spanner 查詢最佳化器會自動僅使用次要索引。查詢原始資料表中各欄時,如要強制使用某一索引,您必須在 SQL 陳述式中使用 FORCE INDEX 指令,例如︰
SELECT *
FROM MyTable@{FORCE_INDEX=MyTableIndex}
WHERE IndexedColumn=@value
您可以對某資料欄定義一個 UNIQUE
索引,以強制使該資料表欄內的值不重複。索引將阻止您新增重複的值。
以下是為 Albums 資料表建立次要索引的 DDL 陳述式範例︰
CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);
若您在資料載入之後建立額外的索引,填入索引可能需要一些時間。建議您將新增索引的頻率限制為平均每天三次。如需建立次要索引的詳細說明,請參閱「次要索引」。如要進一步瞭解索引建立的限制,請參閱結構定義更新。
步驟 2:翻譯任何 SQL 查詢
Spanner 使用附擴充功能的 ANSI 2011 SQL 方言,而且擁有許多函式和運算子,以協助翻譯及匯總您的資料。任何使用 MySQL 特定方言、函式和類型的 SQL 查詢都需要轉換,以便與 Spanner 相容。
雖然 Spanner 不支援以結構化資料做為欄定義,但 SQL 查詢中可以利用 ARRAY<>
和 STRUCT<>
類型,而使用結構化資料。例如,您可以撰寫查詢,在單一查詢中使用 STRUCT
的 ARRAY
(利用預先彙整的資料),傳回某位藝人的所有專輯。詳情請參閱說明文件的「子查詢」一節。
您可以使用 Google Cloud 主控台中的 Spanner Studio 頁面來執行查詢,以分析 SQL 查詢的效能。對大型資料表進行全資料表掃描的查詢通常非常昂貴,應該謹慎使用。如要進一步瞭解如何將 SQL 查詢最佳化,請參閱 SQL 最佳做法說明文件。
步驟 3:遷移應用程式以使用 Spanner
Spanner 提供了一組包含各種語言的用戶端程式庫,以及使用 Spanner 特定 API 呼叫、SQL 查詢和資料修改語言 (DML) 陳述式讀取或寫入資料的功能。使用 API 呼叫對於某些查詢 (例如直接依鍵值讀取列) 可能更迅速,因為不需要翻譯 SQL 陳述式。
Spanner 為 Java 應用程式提供 JDBC 驅動程式。
在遷移程序中,Spanner 無法使用的功能必須在應用程式中實施。例如,驗證資料值並更新相關資料表的觸發條件必須在應用程式中使用讀取/寫入交易來實施,以讀取現有的列,驗證限制條件,然後將更新過的列寫入兩個資料表。
Spanner 提供讀寫和唯讀交易,確保資料的外部一致性。此外,讀取交易可以套用時間戳記邊界,讓您讀取在以下方式中指定的一致性資料版本︰
- 過去的精確時間 (最多 1 小時以前)。
- 在未來 (讀取將被封鎖,直至到達該時刻為止)。
- 傳回到過去某一時間的一致性資料檢視 (具有可接受的有限過時性),不需檢查另一複本上是否有較新的資料。這樣可以獲得效能益處,但代價是資料可能過時。
步驟 4:將資料從 MySQL 轉移至 Spanner
為了將資料從 MySQL 轉移到 Spanner,您必須將 MySQL 資料庫以可攜帶的檔案格式 (例如 XML) 匯出,然後使用 Dataflow 將該資料匯入 Spanner。
從 MySQL 大量匯出
包含 MySQL 的 mysqldump
工具能將整個資料庫匯出成格式正確 XML 檔。或者,您也可以使用 SELECT ... INTO OUTFILE
SQL 陳述式為每個表建立 CSV 檔案。然而,此方法一次只能匯出一個資料表,這表示您必須暫停應用程式或停用資料庫,讓資料庫維持於匯出的一致狀態。
匯出資料檔後,建議您將其上傳至 Cloud Storage 值區,以便將之匯入。
大量匯入至 Spanner
由於 MySQL 和 Spanner 的資料庫結構定義可能不相同,您可能需要做一些資料轉換,這是匯入過程的一部分。執行這些資料轉換,並匯入 Spanner 最容易的方法是使用 Dataflow。Dataflow 是 Google Cloud 分散式擷取、轉換及載入 (ETL) 服務。此為執行使用 Apache Beam SDK 撰寫的資料管道提供一個平台,以便在多部機器上平行讀取和處理大量資料。
Apache Beam SDK 要求您撰寫一個簡單的 Java 程式,以設定讀取、轉換和寫入資料。Cloud Storage 和 Spanner 都存在 Beam 連接器,因此唯一需要撰寫的程式碼是資料轉換本身。
如要取得一個從 CSV 檔案讀取簡單的管道範例,請參閱範例程式碼存放區。
如果您的 Spanner 結構定義中使用了父項─子項交錯資料表,則匯入過程中必須留意,讓父項列在子項列之前建立。Spanner 匯入管道程式碼會先匯入根層次的所有資料,接下來是所有第一層子項資料表,然後是所有的第二層子項資料表,依此類推,以處理這個問題。
您可以直接使用 Spanner 匯入管道大量匯入資料,但您的資料必須使用正確的結構定義,並以 Avro 檔案形式存在。
步驟 5:維持兩個資料庫之間的一致性
許多應用程式都有可用性要求,因此無法離線匯出和匯入資料。因此,當您將資料轉移到 Spanner 時,應用程式仍會繼續修改現有的資料庫。因此,當應用程式執行時,您必須複製對 Spanner 資料庫的更新。
有許多方法可以維持兩個資料庫同步,包括變更資料擷取,以及在應用程式中實施同時更新。
變更資料擷取
MySQL 沒有原生的變更資料擷取 (CDC) 單元。但是有幾種開放原始碼專案,可用來接收 MySQL binlog 並將其轉換為 CDC 串流,例如 Maxwell's daemon 可對資料庫提供 CDC 串流。
您可以開發一套應用程式訂閱此串流,並將相同的修改套用在您的 Spanner 資料庫上 (但當然要先經過資料轉換後再套用)。
從應用程式同時更新兩個資料庫
另一種方法是修改應用程式,以執行對兩個資料庫的寫入。一個資料庫 (最初是 MySQL) 將被視為事實來源,而且在每一次資料庫寫入之後,會讀取一整列,進行轉換,然後寫入 Spanner 資料庫。如此一來,應用程式將不斷地以最新資料覆寫 Spanner 列。
當您確信所有資料都已經正確轉移之後,可以將事實來源切換至 Spanner 資料庫。如果在切換至 Spanner 時發現問題,此機制提供復原的路徑。
驗證資料一致性
當資料流入 Spanner 資料庫時,您可以定期執行比較 Spanner 資料和 MySQL 資料,以確認資料是一致的。您可以查詢兩個資料來源,並比較結果,以驗證一致性。
您可以使用 Dataflow,利用彙整轉換對大型資料集進行詳細的比較。此轉換會使用兩個具有鍵值的資料集,並依據鍵值比對各值。接下來可以比較被匹配的值是否相等。您可以定期執行此一驗證,直到一致性等級符合您的公司需求。
步驟 6:切換至 Spanner,做為應用程式的事實來源
當您對資料遷移有信心時,您可以將應用程式切換為使用 Spanner 做為事實來源。繼續將變更寫回 MySQL 資料庫,讓 MySQL 資料庫維持於最新狀態,萬一出現問題,您還可以復原。
最後,您可以停用並移除 MySQL 資料庫更新程式碼,並關閉 MySQL 資料庫。
匯出及匯入 Spanner 資料庫
您可以選擇性使用 Dataflow 範本執行匯出,將資料表從 Spanner 匯出至 Cloud Storage 值區。產生的資料夾包含一組 Avro 檔案和 JSON 資訊清單檔案,其中包含已匯出的資料表。這些檔案可以使用於各種用途,其中包括︰
- 備份資料庫,以實現資料保留政策合規性或用於災難復原。
- 將 Avro 檔案匯入 BigQuery 等其他 Google Cloud 產品。
如要進一步瞭解匯出和匯入程序,請參閱「匯出資料庫」和「匯入資料庫」。
後續步驟
- 瞭解如何最佳化 Spanner 結構定義。
- 瞭解如何將 Dataflow 用於更複雜的情況。