使用 db2look 模擬數據庫?
我正在將一些數據庫從 iso8859-1 遷移到 utf-8。其中一個數據庫包含 1000 多個表、大量程序、函式、觸發器、約束等。我想盡可能地自動化該過程,因為這將發生多次,並且適用於系統的多個實例。理想情況下,我想把工作交給我的朋友 Jenkins 和 Ansible ;-)
我的計劃是使用 db2look 生成 ddl,但它無法以正確的順序生成“對象”。我嘗試在有和沒有 -ct 標誌的情況下執行(由於不同的原因而失敗)。例如:
connect to <db>; create table t1 (x int not null); create unique index t1pk on t1 (x); alter table t1 add constraint t1pk primary key (x); connect reset;
跑步
db2look -d <db> -e -td @ -ct
為索引和約束生成錯誤的順序。
CREATE TABLE "DB2INST1"."T1" ( "X" INTEGER NOT NULL ) IN "USERSPACE1" ORGANIZE BY ROW@ ALTER TABLE "DB2INST1"."T1" ADD CONSTRAINT "T1PK" PRIMARY KEY ("X")@ CREATE UNIQUE INDEX "DB2INST1"."T1PK" ON "DB2INST1"."T1" ("X" ASC) COMPRESS NO INCLUDE NULL KEYS ALLOW REVERSE SCANS@
刪除 -ct 在這個簡單的範例中有效,但在實際數據庫中由於其他依賴關係而失敗。
我想遷移到 UTF-8 是一項非常常見的任務,所以我很好奇人們做了什麼。我看到的兩種可能的解決方案是:
a) write a parser that inspects the catalog for database objects and sort them topologically using dependency tables. b) write a parser that reads the output from db2look, identify each object and sort them topologically using dependency tables.
顯然這兩者都有缺點,我是否忽略了一些遷移數據庫的簡單方法?
編輯:另一個觀察結果是,只要與通過唯一/主鍵約束隱式創建的索引相比,索引不包含任何額外屬性,
QL0605W
就會引發警告。另一方面,如果指定了附加屬性,SQL0601N
則會引發錯誤。例子:CREATE UNIQUE INDEX X1 ON T1 (C1, C2) COMPRESS NO INCLUDE NULL KEYS DISALLOW REVERSE SCANS
SQL0605W
如果通過主鍵語句創建了類似的索引,則會生成警告。另一方面,索引如下:
CREATE UNIQUE INDEX X2 ON T2 (C1, C2) INCLUDE (C3) CLUSTER COMPRESS NO INCLUDE NULL KEYS ALLOW REVERSE SCANS
產生錯誤
SQL0601N
。我認為這是由於 INCLUDE 子句造成的,但也許 CLUSTER 子句也會導致這種行為。
關於如何以正確順序獲取數據庫對象的粗略想法。依賴關係圖不完整,但似乎滿足了我的需求。
#!/usr/bin/python3 import ibm_db import ibm_db_dbi from toposort import toposort, toposort_flatten cfg = ... conn = ibm_db.connect("DATABASE=%s;HOSTNAME=%s;PORT=50000;PROTOCOL=TCPIP;UID=%s; PWD=%s" % cfg,"","") find_edges = """ select * from ( SELECT 'CONSTRAINT' as type, CONSTNAME, TABSCHEMA, TABNAME, BTYPE, 'N/A', BSCHEMA, BNAME FROM SYSCAT.CONSTDEP WHERE TABSCHEMA NOT LIKE 'SYS%' AND BSCHEMA NOT LIKE 'SYS%' UNION ALL SELECT 'I', 'N/A', D.INDSCHEMA, D.INDNAME, D.BTYPE, 'N/A', D.BSCHEMA, D.BNAME FROM SYSCAT.INDEXDEP D JOIN SYSCAT.INDEXES I ON D.INDSCHEMA = I.INDSCHEMA AND D.INDNAME = I.INDNAME WHERE I.TABSCHEMA NOT LIKE 'SYS%' UNION ALL SELECT 'I', 'N/A', I.INDSCHEMA, I.INDNAME, 'T', 'N/A', I.TABSCHEMA, I.TABNAME FROM SYSCAT.INDEXES I WHERE I.TABSCHEMA NOT LIKE 'SYS%' UNION ALL SELECT 'F', 'N/A', R1.ROUTINESCHEMA, R1.ROUTINENAME, D.BTYPE, 'N/A' , COALESCE(R2.ROUTINESCHEMA, D.BSCHEMA), COALESCE(R2.ROUTINENAME, D.BNAME) FROM SYSCAT.ROUTINEDEP D JOIN SYSCAT.ROUTINES R1 ON D.ROUTINESCHEMA = R1.ROUTINESCHEMA AND D.SPECIFICNAME = R1.SPECIFICNAME LEFT JOIN SYSCAT.ROUTINES R2 ON D.BSCHEMA = R2.ROUTINESCHEMA AND D.BNAME = R2.SPECIFICNAME AND D.BTYPE = 'F' WHERE D.ROUTINESCHEMA NOT LIKE 'SYS%' AND D.BSCHEMA NOT LIKE 'SYS%' AND D.BTYPE <> 'K' UNION ALL SELECT 'T', 'N/A', TABSCHEMA, TABNAME, BTYPE, 'N/A', BSCHEMA, BNAME FROM SYSCAT.TABDEP WHERE TABSCHEMA NOT LIKE 'SYS%' AND BSCHEMA NOT LIKE 'SYS%' UNION ALL SELECT 'X', 'N/A', TRIGSCHEMA, TRIGNAME, BTYPE, 'N/A', BSCHEMA, BNAME FROM SYSCAT.TRIGDEP WHERE TRIGSCHEMA NOT LIKE 'SYS%' AND BSCHEMA NOT LIKE 'SYS%' UNION ALL SELECT 'T', 'N/A', TABSCHEMA, TABNAME, 'T', 'N/A', REFTABSCHEMA, REFTABNAME FROM SYSCAT.REFERENCES WHERE TABSCHEMA NOT LIKE 'SYS%' ORDER BY 3,4 ) """ sedges = ibm_db.prepare(conn, find_edges) edges = {} ibm_db.execute(sedges, ()) lastnode = None tpl = ibm_db.fetch_tuple(sedges) while tpl: n1 = (tpl[0], tpl[1], tpl[2], tpl[3]) n2 = (tpl[4], tpl[5], tpl[6], tpl[7]) if lastnode == n1: edges[n1].add(n2) else: # print("new") edges[n1] = set() edges[n1].add(n2) lastnode = n1 tpl = ibm_db.fetch_tuple(sedges) x = list(toposort_flatten(edges))
現在,x 可用於從 db2look 中以正確的順序挑選內容。我使用了一個簡單的解析器,它將輸出讀取
db2look
到列表中。通過循環 x 並從正確的儲存桶中選擇定義,可以實現排序輸出。解析器本身只是一堆正則表達式,並不是特別有趣,但是由於語句分佈在幾行中,因此最好有一個 stmt 閱讀器:# helper for reading stmt by stmt def myreadlines(f, newline): buf = "" while True: while newline in buf: pos = buf.index(newline) yield buf[:pos] buf = buf[pos + len(newline):] chunk = f.read(4096) if not chunk: yield buf break buf += chunk
編輯:我在https://github.com/lelle1234/Db2Utils有一個解析器。它絕不是完整的,但可以滿足我的需要。
那裡還有一個索引顧問,它試圖為給定的查詢和數據庫提供一組最佳索引。
幾年前,我們將 DB2 從 9.7 遷移到 10.5。我們還將數據庫移至新硬體並實施了數據壓縮。因此,我們決定從頭開始創建數據庫並導出和導入數據。
我們使用 db2look 和 db2move 來完成這項工作。但是,無法以正確的順序獲取 db2look 創建的 DDL。我們不得不將生成的腳本分成不同的部分來創建表、創建觸發器、創建索引等。
最後我們完成以下步驟:
- 導出現有數據
- 創建新數據庫
- 創建緩衝池和表空間
- 創建表
- 創建主鍵
- 創建索引
- 創建視圖
- 載入數據
- 執行重組和執行統計
- 創建儲存過程、使用者定義的函式和触發器
我希望它有所幫助,即使它不是您可能期望的答案。