全部產品
Search
文件中心

ApsaraDB RDS:線上資料分割函數(rds_online_migrate)

更新時間:Dec 12, 2025

RDS PostgreSQL的rds_online_migrate外掛程式提供了線上資料分割函數,可以將普通錶轉換為分區表。

背景

隨著業務發展,資料量會逐漸增多,在特定情境下,可能需要將普通錶轉換為分區表,但是原生PostgreSQL資料庫並沒有提供將普通錶轉換為分區表的線上資料分割函數。為了簡化營運操作,降低分區行為對業務的影響,RDS PostgreSQL提供了線上資料分割函數。

適用範圍

RDS PostgreSQL執行個體版本需要滿足以下條件:

  • 執行個體大版本:13或以上版本。

  • 核心小版本:大於等於20251130。

注意事項

在執行線上分區操作前,請詳細閱讀並確認以下事項,以確保資料安全和操作成功。

  • 前置準備

    • 備份與測試:執行任何操作前,務必確認已有有效全量備份組,並在非生產環境中完成充分的演練與驗證。

    • 儲存空間規劃:線上分區過程中,系統會建立一張新表用於資料移轉。因此,需要預留至少為原表及其所有索引總大小兩倍以上的儲存空間。

    • 資料庫參數配置:此功能依賴邏輯解碼(Logical Decoding)實現,需將wal_level參數設定為logical。此外,若需並存執行多個分區任務,可能需要相應調高max_worker_processes參數的值。

  • 表結構與許可權要求

    • 主鍵或唯一標識:由於功能內部基於PostgreSQL的原生邏輯複製,源表必須擁有主鍵(PRIMARY KEY)或已設定REPLICA IDENTITY

    • 使用者權限:執行操作的使用者帳號必須具備以下許可權:建立publicationsubscriptionreplication slot的許可權,以及對源表和目標表執行RENAME操作的許可權。

    • 許可權一致性:為確保商務持續性,遷移前請授予業務帳號對目標資料分割表的相應操作許可權,確保其許可權與源表一致。

  • 異常處理與風險

    • 非原子性操作:此功能為指令碼化流程,不具備原子性。若執行過程中發生異常中斷,可能導致內部對象殘留。

    • 手動清理:發生異常中斷後,可能需要手動清理報錯日誌中殘留的rds_online_migrate.internal_map表記錄、publicationsubscriptionreplication slot對象。請參考以下命令進行清理:

      -- 清理中繼資料記錄
      DELETE FROM rds_online_migrate.internal_map WHERE src_relname = 'source_table' AND dst_relname = 'destination_table';
      
      -- 刪除殘留的發布
      DROP PUBLICATION publication_name;
      
      -- 刪除殘留的訂閱
      DROP SUBSCRIPTION subscription_name;
      
      -- 刪除殘留的複製槽
      SELECT pg_drop_replication_slot('slot_name');
  • RENAME 操作的潛在影響

    • 關聯對象重建RENAME操作完成後,依賴於原表的視圖(View)、觸發器(Trigger)和外鍵約束需要手動重建。

    • 邏輯複製影響:若源表已加入其他邏輯複製任務,RENAME操作可能會中斷該複製鏈路。操作完成後,需將新表(原目標表)重新添加到相應的publication中。

  • 功能適用情境擴充

    • 該功能同樣支援對已有分區表進行線上重分區。

使用樣本

以下樣本將示範如何將一個名為 public.test 的普通表線上轉換為分區表。

1. 設定資料庫參數

rds_online_migrate功能依賴邏輯解碼(Logical Decoding)。在RDS控制台中將wal_level參數設定為logical

2. 準備源表和資料

建立一個普通表public.test作為轉換的源表,並插入一百萬行測試資料,以類比業務真實情境。

-- 建立源表
CREATE TABLE public.test(id int4 PRIMARY KEY, info text);

-- 插入類比資料
INSERT INTO public.test SELECT x, repeat(x::text, 2) FROM generate_series(1, 1000000) AS x;

3. 安裝外掛程式

在需要執行操作的資料庫中建立rds_online_migrate外掛程式。

CREATE EXTENSION rds_online_migrate;

4. 建立目標資料分割表

建立一個與源表結構相同的目標資料分割表public.test_p。該表必須與源表位於同一Schema下。本樣本建立一個按ID雜湊分割的表,包含四個子分區。

CREATE TABLE public.test_p (LIKE test INCLUDING ALL) PARTITION BY HASH(id);
CREATE TABLE public.test_p_0 PARTITION OF public.test_p FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE public.test_p_1 PARTITION OF public.test_p FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE public.test_p_2 PARTITION OF public.test_p FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE public.test_p_3 PARTITION OF public.test_p FOR VALUES WITH (MODULUS 4, REMAINDER 3);

5. 執行線上轉換

調用rds_online_migrate.rewrite_table函數啟動線上分區流程。函數的第一個參數是源表名稱,第二個參數是目標資料分割表名稱。函數返回t表示執行成功。

SELECT rds_online_migrate.rewrite_table('public.test', 'public.test_p');
-- 預期輸出:
 rewrite_table
---------------
 t
(1 row)

6. 驗證轉換結果

操作成功後,函數會自動完成表名切換,以保證業務的無縫過渡:

  • 原表public.test被重新命名為public.test_rds_bkp,作為資料備份,供後續驗證,可自行刪除。

  • 目標資料分割表public.test_p被重新命名為public.test,作為新表使用。

接下來,通過以下步驟進行驗證:

  • 檢查表結構 使用\d命令查看關係列表,確認表名已按預期切換,並且新的test表類型為 partitioned table

    testdb=> \d
    -- 預期輸出:
                       List of relations
     Schema |     Name     |       Type        |   Owner
    --------+--------------+-------------------+-----------
     public | test         | partitioned table | rds_super
     public | test_p_0     | table             | rds_super
     public | test_p_1     | table             | rds_super
     public | test_p_2     | table             | rds_super
     public | test_p_3     | table             | rds_super
     public | test_rds_bkp | table             | rds_super
    (6 rows)
  • 驗證資料完整性 分別查詢新表、備份表和各分區的資料行數,確保資料移轉完整且分布正確。

    1. 查詢備份表總行數,應與遷移前一致。

      SELECT count(*) FROM public.test_rds_bkp;
      -- 預期輸出:1000000
    2. 查詢新分區表總行數,應與備份表一致。

      SELECT count(*) FROM public.test;
      -- 預期輸出:1000000
    3. 查詢各分區行數,驗證資料已按雜湊規則分布到各子表。

      SELECT count(*) FROM public.test_p_0;
      -- 預期輸出:249589
      SELECT count(*) FROM public.test_p_1;
      -- 預期輸出:250376
      SELECT count(*) FROM public.test_p_2;
      -- 預期輸出:249786
      SELECT count(*) FROM public.test_p_3;
      -- 預期輸出:250249