Usando db2look per imitare un database?
Su Febbraio 14, 2021 da adminSto eseguendo la migrazione di alcuni database da iso8859-1 a utf-8. Uno dei database contiene più di 1000 tabelle, un sacco di procedure, funzioni, trigger, vincoli ecc. Vorrei automatizzare il processo il più possibile poiché questo accadrà più volte e per diverse istanze del sistema. Idealmente vorrei cedere il lavoro ai miei amici Jenkins e Ansible 😉
Il mio piano era di generare il ddl con db2look, ma non riesce a generare gli “oggetti” nellordine corretto. Ho provato a eseguire sia con che senza il flag -ct (fallisce per diversi motivi) . Ad esempio:
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;
in esecuzione
db2look -d <db> -e -td @ -ct
genera lordine sbagliato per lindice e il vincolo.
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@
La rimozione di -ct funziona in questo banale esempio, ma fallisce nel database effettivo a causa di altre dipendenze.
Immagino che la migrazione a UTF-8 sia unattività abbastanza comune, quindi sono curioso di sapere cosa p persone hanno fatto. Le due possibili soluzioni che vedo sono le seguenti:
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.
Chiaramente ci sono degli svantaggi con entrambi, sto trascurando qualche modo banale per migrare i database?
MODIFICA: unosservazione aggiuntiva è che fintanto che un indice non contiene attributi extra rispetto allindice creato implicitamente tramite un vincolo di chiave univoca / primaria, un avviso QL0605W
viene sollevato. Se invece vengono specificati attributi aggiuntivi, viene generato un errore SQL0601N
. Esempio:
CREATE UNIQUE INDEX X1 ON T1 (C1, C2) COMPRESS NO INCLUDE NULL KEYS DISALLOW REVERSE SCANS
genera un avviso SQL0605W
se un indice simile viene creato tramite listruzione della chiave primaria.
Daltra parte un indice come:
CREATE UNIQUE INDEX X2 ON T2 (C1, C2) INCLUDE (C3) CLUSTER COMPRESS NO INCLUDE NULL KEYS ALLOW REVERSE SCANS
genera un errore SQL0601N
. Presumo che ciò sia dovuto alla clausola INCLUDE, ma forse anche la clausola CLUSTER causerà questo comportamento.
Commenti
Risposta
Alcuni anni fa abbiamo migrato il nostro DB2 da 9.7 a 10.5. Abbiamo anche spostato il database su un nuovo hardware e implementato la compressione dei dati. Per questo motivo abbiamo deciso di creare il database da zero ed esportare e importare i dati.
Abbiamo usato db2look e db2move per fare il lavoro. Tuttavia, non era possibile ottenere il DDL creato da db2look nellordine corretto. Abbiamo dovuto dividere lo script generato in diverse parti per creare tabelle, creare trigger, creare indici, ecc.
Infine ci ritroviamo con i seguenti passaggi:
- esportare il dati esistenti
- crea il nuovo database
- crea bufferpool e tablespace
- crea tabelle
- crea chiavi primarie
- creare indici
- creare viste
- caricare dati
- eseguire reorg e runstats
- creare procedure memorizzate, funzioni definite dallutente e trigger
Spero che aiuti, anche se non è la risposta che potresti aspettarti.
Commenti
- Grazie per la tua risposta. La situazione è un po più complicata (ci sono ad esempio tabelle che dipendono da funzioni e viceversa). ‘ probabilmente creerò un parser che ordina loutput da db2look in ordine topologico utilizzando le tabelle delle dipendenze.
Risposta
Idea approssimativa su come ottenere gli oggetti del database nellordine corretto. Il grafico delle dipendenze non è completo ma sembra soddisfare le mie esigenze.
#!/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))
Ora, x può essere utilizzato per selezionare le cose nellordine corretto da db2look. Ho usato un banale parser che legge loutput di db2look
negli elenchi. Eseguendo un ciclo su x e selezionando la definizione dal bucket destro, è possibile ottenere un output ordinato. Il parser stesso è solo un mucchio di espressioni regolari e non particolarmente interessante, ma poiché le istruzioni sono distribuite su più righe, è bello avere un lettore 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
EDIT: ho un parser su https://github.com/lelle1234/Db2Utils . Non è affatto completo ma ha funzionato per le mie esigenze.
Cè anche un index advisor che cerca di trovare un insieme ottimale di indici per una data query e un database.
Risposta
Ho utilizzato il seguente approccio per copiare lo schema di produzione per testare i server per gli sviluppatori. Il trucco è ignorare gli errori durante le singole esecuzioni e confrontare lo schema alla fine per assicurarsi che tutto sia ricreato correttamente. So che non è un approccio pulito. Lho fatto su uno schema con oltre 1000 tabelle, 500 funzioni con dipendenze, vincoli, ecc. È possibile automatizzare i passaggi utilizzando script di shell. Richiede molto meno sforzo rispetto alla scrittura del parser e al suo test.
Passaggio 1 Utilizzare lo script per estrarre lo schema dal server di produzione in un ordine specifico (db2look per i tablespace prima, db2look per le tabelle dopo, ecc.). Lutilizzo di un ordine specifico riduce il numero di iterazioni per il passaggio 2 & 3.
Passaggio 2 Esegui loutput del passaggio 1 sul server di prova
Passaggio 3 Estrai lo schema dal server di prova e confrontalo con lo schema dal server di produzione
Passaggio 4 Ripeti i passaggi 2 e 3, finché entrambi gli schemi non sono sincronizzati.
AUTO_REVAL
perDEFERRED_FORCE
risolvere il tuo problema?db2 +c -s ...
) in modo da poter affermare con sicurezza che tutto è ricreato correttamente.