簡介
目前大多企業 DB2 生產環境都要求高可用,不能承擔片刻停機帶來的損失。當 DBA 希望將表從一個表空間移動到另一個表空間中,在 DB2 V9.7 以前的版本中要實現這個目標比較復雜,總有一段時間表對外是不可用的。DB2 V9.7 提供了 ADMIN_MOVE_TABLE 存儲過程將表中的數據移至名稱相同的新表對象,而新表是存放在不同的表空間上具有不同的存儲特征,同時數據保持聯機可供訪問。我們還可以在表移動時為表生成新的優化壓縮字典。
DB2 V9.7 通過自動將表數據移至新表對象並同時允許數據保持聯機以進行查詢、插入、更新和刪除訪問,降低了企業的總體擁有成本(TCO)和復雜性。
在表數據移動過程中我們還可以使用 ADMIN_MOVE_TABLE 存儲過程修改表的定義,如增加刪除列、修改列數據類型等。
在線數據移動過程
ADMIN_MOVE_TABLE 過程涉及三個表:
源表。源表是指數據將被移動走的表,通過參數形式傳遞給 ADMIN_MOVE_TABLE 存儲 過程。
目標表。目標表由 ADMIN_MOVE_TABLE 根據傳遞入的參數定義新創建的表,所有源表中的數據將復制到目標表中,並且最後被命名成與源表相同的表名。
登台表。由 ADMIN_MOVE_TABLE 存儲 過程創建,在表移動過程中用於臨時保持對源表的所有 Update、Insert、Delete 操作。當移動完成後,該表將被刪除。
數據移動過程還涉及一個表被成為協議表(protocol table),這個表將用於保存數據移動的過程數據和配置信息,如數據移動使用的參數、COPY 開始的時間、結束時間、COPY 使用的選項等。此表定義如下:
清單 1. 協議表的定義 C:\>db2 describe table systools.ADMIN_MOVE_TABLE
數據類型 列
列名 模式 數據類型名稱 長 小數位 NULL
--------------- --------- ------------------- ---------- ----- -
-----
TABSCHEMA SYSIBM VARCHAR 128 0 否
TABNAME SYSIBM VARCHAR 128 0 否
KEY SYSIBM VARCHAR 32 0 否
VALUE SYSIBM CLOB 10485760 0 是
其中關鍵字(KEY)都有特定含義,當我們對表數據移動進行問題診斷、調整性能時都會使用到該表。
ADMIN_MOVE_TABLE 過程將首先創建源表的影子副本。在復制階段,DB2 將使用觸發器捕獲對源表的插入、更新和刪除操作並將其放入到登台表中。完成復制階段後,DB2 在登台表中捕獲的數據更改操作將在影子副本中重現。最後 DB2 使用 ADMIN_MOVE_TABLE 過程將使表短暫脫機以交換對象名。ADMIN_MOVE_TABLE 默認情況下使用 INSERT Cursor 的方式將數據從源表復制到目標表,也可以指定選項使用 LOAD 方式復制數據以提高性能。
從過程上看,表數據移動大致分為以下幾個階段:
INIT 階段。本階段驗證數據移動是否可以發生,並且初始化後繼數據移動所需要的各種數據,如目標表、登台表、源表觸發器。
COPY 階段。本階段將源表中的所有數據復制到 INIT階段創建的目標表中,如果在此時有用戶對源表執行 DML語句,則 INIT階段創建的觸發器將會捕獲到這些語句,並且將任何更新、刪除、插入操作保存到登台表中。在復制階段結束後,如果我們沒有使用 COPY_WITH_INDEXES選項,則目標表上將會建立新的索引。而且如果需要的話,源表、目標表上將會建立輔助索引幫助提高 REPLAY階段的性能。COPY階段只能在 INIT階段完成後開始。
REPLAY 階段。在 COPY階段保存到登記表的所有數據將在本階段被 Replay到目標表。REPLAY階段只能在 COPY階段完成後開始。
VERIFY 階段。本階段是可選的,用於檢查目標表和源表是否在內容上等同。檢查過程首先在源表、目標表上獲取 S鎖,然後 Replay源表上的所有變化,然後與目標表進行比較。如果表擁有唯一索引,則會比較兩個表中都存在的列的所有值,如果沒有唯一索引將不比較 LONG、LOB、XNML列的值。.驗證工作是一個成本很高的操作,我們在使用時必須要判斷是否真的需要這麼做。VERIFY階段只能在 COPY階段或者 REPLAY階段完成後開始。
SWAP 階段。在 Replay階段完成後或者達到協議表中保存的 REPLAY_THRESHOLD值設置時,源表將被脫機,然後 DB2交互源表和目標表的名字,重新把表聯機。SWAP階段可以在 COPY完成後啟動,最好時在 REPLAY調用完成後啟動。
CLEANUP 階段。本階段將會刪除在 INIT階段創建的登台表,觸發器。如果調用過程中沒有使用 KEEP選項,源表也將會被刪除。CLEANUP階段可以在 SWAP階段之後被調用。
我們需要注意的是 ADMIN_MOVE_TABLE 可以將源表上定義的觸發器、視圖也同時移動到目標表,但是當前它並不能支持將外鍵關系復制到目標表,無論源表是外鍵的父表還是子表。因此如果源表上有外鍵關系存在,我們首先需要捕獲這些外鍵定義,然後在移動完成後在目標表上重新創建。
ADMIN_MOVE_TABLE 語法
DB2 中存在兩種合法的 ADMIN_MOVE_TABLE 語法形式。第一種方法用於我們修改在目標表上修改指定的部分的定義,如我們有一個定義很長的表,而我們希望做的僅僅時修改表存放的表空間,用第一種語法我們就不需要重新創建表而直接使用 ADMIN_MOVE_TABLE 修改。我們需要做的僅僅是在參數中指定 data_tbsp、index_tbsp、和 lob_tbsp,而把其他可選參數設置為空即可。
DB2 提供的第二種語法讓我們更加靈活、方便的控制目標表的創建,而不使用存儲過程創建目標表。這讓我們能夠在第一種方法沒有辦法創建目標表的情況下手工創建目標表。
清單 2. 方法 1 語法 >>-ADMIN_MOVE_TABLE--(--tabschema--,--tabname--,---------------->
>--data_tbsp--,--index_tbsp--,--lob_tbsp--,--mdc_cols--,-------->
.-,-------.
V |
>--partkey_cols--,--data_part--,--coldef--,----options-+--,----->
>--Operation--)------------------------------------------------><
清單 2. 方法 2 語法 >>-ADMIN_MOVE_TABLE--(--tabschema--,--tabname--,---------------->
.-,-------.
V |
>--target_tabname--,----options-+--,--Operation--)-------------><
存儲過程中使用的參數含義如下:
tabschema ,源表模式。
tabname,源表名稱
data_tbsp,指定目標表的新數據存放表空間。如果此參數有值,則 index_tbsp and lob_tbsp 參數需要存在。如果該值未提供,則源表數據表空間用來保持目標表的數據。
index_tbsp,指定目標表的新索引表空間。如果該值被提供,則 data _tbsp and lob_tbsp 參數需要存在。如果該值未被提供,則源表索引表空間被用來保存目標表的索引。
lob_tbsp, 指定目標表的大對象表空間,如果該值被提供,則 data _tbsp and index_tbsp 參數需要存在。如果該參數未指定值,則源表大對象表空間被用來保存目標表的大對象。
mdc_cols,指定目標表的多維列(MDC),多列之間使用逗號隔開。如果值為 NULL 或者’ - ‘,目標表將不會使用 ORGANIZE BY DIMENSIONS 子句創建 MDC 表。如果值為空串或者’ - ‘,DB2 將檢查源表上是否指定了 MDC,如果存在則使用源表的 MDC。
partkey_cols,指定目標表的分區鍵列,多列之間使用逗號隔開。如果值未 NULL 或者’ - ‘,目標表將不會 PARTITIONING KEY 子句創建目標表。如果值為空串或者’ - ‘,DB2 將檢查源表上是否指定了分區鍵,,如果存在則使用源表的分區鍵。
data_part,本參數提供目標表的數據分區詳細規格。本語句定義了如何將表根據表的一個或多個列的值存放在多個存儲目標上。如果值未 NULL 或者’ - ‘,目標表將不會 PARTITIONING RANGE 子句。如果值為空串或者’ - ‘,DB2 將檢查源表上是否指定了分區模式,如果存在則使用源表的分區模式。
coldef,指定目標表的列定義,方便我們將列的修改為兼容的數據類型,不過列名必須相同。該參數提供了增加新列、刪除存在的列功能,只有存在唯一索引或主鍵索引的表中才能刪除列,同時列不能是主鍵或者唯一鍵的一部分。
target_tabname ,指定目標表名稱,在完成數據移動後該名稱將作為新表的名字。當我們指定,目標表的名字時,我們我們可以對目標表進行以下變化:
數據、索引、LOB 表空間可以改變
可以增加或變化多維列(MDC)規格。
可以增加或者變化分區鍵列規格。
可以增加或者變化數據分區規格。
可以啟動或者停止數據壓縮。
可以增加新列。
當指定目標表的名字時,存在以下約束:
源表與目標表的模式必須相同
如果目標表已經存在,則目標表必須為空
不能為類型表、物化查詢表、登台表、遠程表、或者聚集表
選項。多個選項可以使用逗號隔開:
KEEP。該選項將會使源表保存為另外一個名字的 COPY。如源表名為 T1,在數據移動完成後,源表將被命名為 T1AAAAVxo。我們可以在協議表中的 ORIGINAL 關鍵字下找到源表的新名字。
COPY_USE_LOAD。該選項使用不可恢復的 db2Load API 從源表復制數據到目標表。如果使用該選項,則 FORCE 選項需要被包含。
COPY_WITH_INDEXES。此選項指定在 COPY 源表之前創建索引。默認情況下 DB2 時在源表 COPY 後創建索引的。使用該選項的好處是在 COPY 後不在需要每創建一個索引進行一次表掃描,索引創建受需要活動日志的事務控制;缺點是會使得 COPY 的性能下降,因為需要在目標表上維護索引,同時索引上有很多偽刪除的鍵。
FORCE。如果指定此選項 SWAP 階段將不會檢查源表是否修改了其定義。
NO_STATS。該選項指定不啟動對目標表的 Runstats 命令或者復制統計信息。
COPY_STATS。該選項指定在 SWAP 階段之前從源表中復制統計信息到目標表。
NO_AUTO_REVAL。該選項防止自動進行表的 Revalid 操作,而是直接重新創建所有索引、視圖。
REORG。該選項指定在 SWAP 之前對目標表進行脫機重組,可以用於重構數據字典。
Operation。該選項指定期望進行的操作,一般為 MOVE。我們也可以手工把 MOVE 拆分開,依次手工執行 INIT、COPY、REPLAY、VERIFY、SWAP、CLEANUP。當移動到某個階段,我們想取消移動時,可以使用 CANCEL 操作。
ADMIN_MOVE_TABLE_UTIL 的使用
我們知道 DB2 在移動表數據時,會使用表 systools .ADMIN_MOVE_TABLE 保存數據移動配置和狀態信息,該表是以 tabschema、tabname、key 列為主鍵。ADMIN_MOVE_TABLE_UTIL 存儲過程可以用來更改協議表 ADMIN_MOVE_TABLE 中定義的鍵值。
清單 4. ADMIN_MOVE_TABLE_UTIL 語法 >>-ADMIN_MOVE_TABLE_UTIL--(--tabschema--,--tabname--,--action--,--key--,--value--)-><
其中:
Tabschema 指定准備修改的正在移動的表的模式
Tabname 指定准備修改的正在移動的表的名稱
Action 指定存儲過程即將執行的動作,可以取以下執行
UPSERT,插入更新。如果 Key 值指定的關鍵值存在則使用新值更新,否則則在表 ADMIN_MOVE_TABLE 中使用 Key、Value 指定的值插入一行
DELETE,刪除。根據 Tabschema、Tabname、key 指定的刪除表 ADMIN_MOVE_TABLE 中行。
Key 指定准備修改的數據移動過程中的參數。Key 可以取以下值:
COMMIT_AFTER_N_ROWS。指定在 COPY 階段多少行 Commit 一次。默認值為 0 表示 COPY 階段執行過程中不 Commit。
DEEPCOMPRESSION_SAMPLE。如果源表是壓縮的,本參數指定創建壓縮數據字典時采樣數據的大小(KB 為單位)。默認值為 0 表示不采樣。
COPY_ARRAY_SIZE。指定 COPY_ARRAY_INSERT 時 ARRAY 的大小,如果小於或等於 0 表示不使用 COPY_ARRAY_INSERT
COPY_INDEXSCHEMA。在 COPY 階段用於聚焦目標表的索引模式。
COPY_ INDEXNAME。在 COPY 階段用於聚焦目標表的索引名稱。
REPLAY_MAX_ERR_RETRIES。在 REPLAY 階段允許的最大錯誤重試次數。REPLAY 階段經常碰到的錯誤為鎖超時或者死鎖。
REPLAY_THRESHOLD。在一輪 REPLAY 階段過程中,當應用了登台表中指定的行數後,REPLAY 將停止,及時同時登台表中有了新的條目。
REORG_USE_TEMPSPACE。如果我們在表移動中使用了 REORG 選項,我們可以通過本參數指定 REORG 過程中使用的臨時表空間。如果未指定該參數,REORG 將使用與表相同的表空間執行重組。
SWAP_MAX_RETRIES。指定在 SWAP 階段,允許的最大錯誤重試次數。SWAP 階段經常碰到的錯誤為鎖超時或者死鎖。
Value。准備設置 Key 指定關鍵字的值,該參數為 CLOB(10M) 數據類型,可以取 NULL 或空串。
清單 5. ADMIN_MOVE_TABLE_UTIL 例子 CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','INIT')
CALL SYSPROC.ADMIN_MOVE_TABLE_UTIL('SVALENTI','T1','UPSERT',
'DEEPCOMPRESSION_SAMPLE','30720')
CALL SYSPROC.ADMIN_MOVE_TABLE_UTIL('SVALENTI','T1','DELETE','COPY_INDEXSCHEMA','')
CALL SYSPROC.ADMIN_MOVE_TABLE_UTIL('SVALENTI','T1','DELETE','COPY_INDEXNAME','')
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','COPY')
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','REPLAY')
CALL SYSPROC.ADMIN_MOVE_TABLE('SVALENTI','T1','','','','','','','','','SWAP')
上面清單中首先使用默認值啟動數據移動 INIT 階段,然後使用 ADMIN_MOVE_TABLE_UTIL 過程修改壓縮采樣大小為 30720 KB,並刪除 COPY_INDEXSCHEMA、COPY_INDEXNAME 設置,然後繼續數據移動過程。
數據移動例子
使用 DB2 在線表移動功能,我們可以進行:
在線表壓縮。
在表重組或者重分布
在線將表空間轉換為 LARGE 表空間
將數據 / 索引 /LONG 移動到新的不同的表空間
支持表模式變化,如增加列、刪除列、修改列數據類型,增加或修改 MDC 維定義,增加或修改范圍分區鍵、增加或修改表分區鍵
我們首先創建測試表 EMP_TEST,並創建索引,然後向表中插入 10 萬條測試數據。
清單 6. 創建測試表 CREATE TABLE emp_test (
EMPNO INTEGER NOT NULL,
first_name VARCHAR(128) NOT NULL,
last_name VARCHAR(128),
SALARY DECIMAL,
BONUS DECIMAL,
COMM DECIMAL,
CONSTRAINT EMPNO_pk PRIMARY KEY (EMPNO)
)
IN USERSPACE1;
Create index first_name_idx on emp_test(first_name);
Create index last_name_idx on emp_test(last_name);
INSERT INTO emp_test (EMPNO, first_name, last_name,SALARY,BONUS,COMM)
WITH TEMP (COUNTER, first_name, last_name,SALARY,BONUS,COMM) AS
(
VALUES (0,
VARCHAR(MOD(INT(RAND() * 100000), 99999)),
VARCHAR(MOD(INT(RAND() * 100000), 99999)),
MOD(INT(RAND() * 100000), 99999),
MOD(INT(RAND() * 100000), 99999),
MOD(INT(RAND() * 100000), 99999)
)
UNION ALL
SELECT
(COUNTER + 1),
VARCHAR(MOD(INT(RAND() * 100000), 99999)),
VARCHAR(MOD(INT(RAND() * 100000), 99999)),
MOD(INT(RAND() * 100000), 99999),
MOD(INT(RAND() * 100000), 99999),
MOD(INT(RAND() * 100000), 99999)
FROM
TEMP
WHERE
(COUNTER + 1) < 100000
)
SELECT
COUNTER, first_name, last_name,SALARY,BONUS,COMM
FROM
TEMP
;
runstats on table db2admin.emp_test and indexes all;
測試一:移動表到新表空間
我們創建測試表空間 TS_TEST,然後將 EMP_TEST 中的數據、索引、LONG 對象全部移動到 TS_TEST 表空間中。
CREATE TABLESPACE TS_TEST;
CALL SYSPROC.ADMIN_MOVE_TABLE
('DB2ADMIN', 'EMP_TEST',
'TS_TEST', 'TS_TEST', 'TS_TEST',
'', '', '', '', '', 'MOVE');
結果集 1
--------------
KEY VALUE
-------------------------- ------------------------
AUTHID USERID
CLEANUP_END 2009-08-18-14.38.40.390000
CLEANUP_START 2009-08-18-14.38.39.827000
COPY_END 2009-08-18-14.38.29.546000
COPY_OPTS OVER_INDEX,ARRAY_INSERT
COPY_START 2009-08-18-14.38.20.452000
COPY_TOTAL_ROWS 100000
INDEXNAME EMPNO_PK
INDEXSCHEMA USERID
INDEX_CREATION_TOTAL_TIME 7
INIT_END 2009-08-18-14.38.20.311000
INIT_START 2009-08-18-14.38.19.124000
REPLAY_END 2009-08-18-14.38.38.905000
REPLAY_START 2009-08-18-14.38.29.561000
REPLAY_TOTAL_ROWS 0
REPLAY_TOTAL_TIME 0
STATUS COMPLETE
SWAP_END 2009-08-18-14.38.39.733000
SWAP_RETRIES 0
SWAP_START 2009-08-18-14.38.39.108000
VERSION 09.07.0000
21 條記錄已選擇。
返回狀態 = 0
數據移動結果集實際上是從協議表 ADMIN_MOVE_TABLE 中選擇出來的數據。結果集顯示 COPY 10 萬行數據花費了 9.1 秒,REPLAY 花費 9.4 秒,SWAP 花費 0.6 秒,合計 21.1 秒,這表明數據移動過程絕大部分時間花費在 COPY 和 REPLAY 階段。如果我們希望能夠優化數據移動過程,應主要從這個階段入手。
測試二:性能優化
在 COPY 有兩個對性能影響比較大的選項,一個為 COPY_WITH_INDEXES,一個為 COPY_USE_LOAD。
COPY_WITH_INDEXES 選擇指定在 COPY 源表之前就創建索引,這樣在復制過程中需要對索引進行維護,因此性能會下降,不過優點是索引創建收到事務保護。默認情況下不使用 COPY_WITH_INDEXES,如果大家在協議表 ADMIN_MOVE_TABLE 的 COPY 選項中發現”WITH_INDEXES”則表示先創建了索引。
DB2 進行表數據移動時,默認采用 INSERT FROM CURSOR 方法進行 COPY,這種方法需要對復制的每一行執行一個 Insert 操作,引起的負擔與我們平時執行 Insert 完全相同。我們可以通過設置選項 COPY_USE_LOAD 采用 LOAD API 方式進行 COPY 以提高性能。使用 LOAD API 的優點是:
LOAD 過程不會對表的每一行記錄日志 .
LOAD 可以利用 CPU 並行性和 IO 並行性
LOAD 可進行大塊 IO,這有利於提高 IO 的效率
不過需要注意的是,使用 LOAD API 時,與使用 LOAD 命令加載數據一樣,過程是不可恢復的。因此最好在 LOAD 後執行一次數據庫備份,或者在 LOAD 時指定選項 COPY 或 KEEP 以保存一份原始數據。
CALL SYSPROC.ADMIN_MOVE_TABLE
('USERID', 'EMP_TEST', 'NEW_TS', 'NEW_TS', 'NEW_TS', '', '', '', '', 'COPY_USE_LOAD,FORCE', 'MOVE')
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
結果集 1
--------------
KEY VALUE
---------------------- ----------------------
AUTHID USERID
CLEANUP_END 2009-08-18-14.44.48.952000
CLEANUP_START 2009-08-18-14.44.48.327000
COPY_END 2009-08-18-14.44.45.155000
COPY_OPTS OVER_INDEX,LOAD,WITH_INDEXES
COPY_START 2009-08-18-14.44.37.171000
COPY_TOTAL_ROWS 100000
INDEXNAME EMPNO_PK
INDEXSCHEMA USERID
INDEX_CREATION_TOTAL_TIME 1
INIT_END 2009-08-18-14.44.36.640000
INIT_START 2009-08-18-14.44.35.436000
REPLAY_END 2009-08-18-14.44.47.186000
REPLAY_START 2009-08-18-14.44.45.155000
REPLAY_TOTAL_ROWS 0
REPLAY_TOTAL_TIME 0
STATUS COMPLETE
SWAP_END 2009-08-18-14.44.48.155000
SWAP_RETRIES 0
SWAP_START 2009-08-18-14.44.47.186000
VERSION 09.07.0000
21 條記錄已選擇。
返回狀態 = 0
上述結果集顯示 COPY 10 萬行數據花費了 8 秒,REPLAY 花費 2 秒,SWAP 花費 1 秒,合計 13.1 秒。在這個例子中我們使用了 COPY_USE_LOAD 選項,即采用 LOAD API 加載數據,比使用 INSERT FROM CURSOR 方法快 36%。
總結
DB2 V9.7 提供的 ADMIN_MOVE_TABLE 存儲過程能夠幫助 DBA 在線的修改表,包括表空間、表定列義、表壓縮、表分區等,這為 DBA 保持系統高可用性。在使用 ADMIN_MOVE_TABLE 存儲過程時,我們也會經常碰到錯誤,主要和表移動狀態有關:
聯機移動表操作所處的狀態不允許執行指定的操作
沒有正在執行中的聯機移動表操作;因此,不允許執行指定的操作。
存在正在執行中的聯機移動表操作;不允許對同一個表執行並行的聯機表移動操作。
該表是聯機表移動操作的目標表、登台表或協議表,因此不可移動。
正在執行現場重組操作,此操作不允許執行聯機移動表操作的復制階段。