db2lookを使用してデータベースを模倣しますか?
On 2月 14, 2021 by admin一部のデータベースをiso8859-1からutf-8に移行中です。データベースの1つには、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への移行は非常に一般的な作業だと思いますので、人々はやった。考えられる2つの解決策は次のとおりです。
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句もこの動作を引き起こします。
コメント
回答
数年前、DB2を9.7から10.5に移行しました。また、データベースを新しいハードウェアに移動し、データ圧縮を実装しました。このため、データベースを最初から作成し、データをエクスポートおよびインポートすることにしました。
db2lookとdb2moveを使用して作業を行いました。ただし、db2lookによって作成されたDDLを正しい順序で取得する方法はありませんでした。テーブルの作成、トリガーの作成、インデックスの作成などのために、生成されたスクリプトをさまざまな部分に分割する必要がありました。
最後に、次の手順を実行します。
- エクスポート既存のデータ
- 新しいデータベースを作成する
- バッファプールとテーブルスペースを作成する
- テーブルを作成する
- 主キーを作成する
- インデックスの作成
- ビューの作成
- データの読み込み
- reorgsとrunstatsの実行
- ストアドプロシージャ、ユーザー定義関数、トリガーの作成
期待した答えではない場合でも、お役に立てば幸いです。
コメント
- ご回答ありがとうございます。状況はもう少し複雑です(たとえば、関数に依存するテーブルがあり、その逆もあります)。 ‘おそらく、依存関係テーブルを使用して、db2lookからの出力をトポロジカル順に並べ替えるパーサーを作成します。
回答
データベースオブジェクトを正しい順序で取得する方法に関する大まかなアイデア。依存関係グラフは完全ではありませんが、私のニーズを満たしているようです。
#!/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 にパーサーがあります。それは決して完全ではありませんが、私のニーズのために機能しました。
特定のクエリとデータベースに最適なインデックスのセットを考え出すインデックスアドバイザーもあります。
回答
次のアプローチを使用して、開発者向けのテストサーバーに本番スキーマをコピーしました。 トリックは、個々の実行中のエラーを無視し、最後にスキーマを比較して、すべてが正しく再作成されていることを確認することです。 私はそれがクリーンなアプローチではないことを知っています。 これは、1000を超えるテーブル、依存関係、制約などを含む500の関数を含むスキーマに対して行いました。シェルスクリプトを使用して手順を自動化できます。 パーサーを作成してテストする場合に比べて、はるかに少ない労力で済みます。
ステップ1スクリプトを使用して、特定の順序で本番サーバーからスキーマを抽出します(db2lookは最初にテーブルスペースを、db2lookは次にテーブルを検索します)。 特定の順序を使用すると、ステップ2 & 3の反復回数が減ります。
ステップ2テストサーバーでステップ1の出力を実行します
ステップ3 テストサーバーからスキーマを抽出し、本番サーバーのスキーマと比較します
ステップ4両方のスキーマが同期するまでステップ2と3を繰り返します。
AUTO_REVAL
データベース構成パラメーターを設定していますかDEFERRED_FORCE
で問題を解決しますか?db2 +c -s ...
)で実行することを好みます。