Verwenden Sie db2look, um eine Datenbank nachzuahmen?
On Februar 14, 2021 by adminIch bin gerade dabei, einige Datenbanken von iso8859-1 nach utf-8 zu migrieren. Eine der Datenbanken enthält mehr als 1000 Tabellen, viele Prozeduren, Funktionen, Trigger, Einschränkungen usw. Ich möchte den Prozess so weit wie möglich automatisieren, da dies mehrmals und für mehrere Instanzen des Systems geschehen wird. Idealerweise möchte ich die Arbeit meinen Freunden Jenkins und Ansible übergeben 😉
Mein Plan war es, die ddl mit db2look zu generieren, aber die „Objekte“ werden nicht in der richtigen Reihenfolge generiert. Ich habe versucht, sowohl mit als auch ohne das Flag -ct auszuführen (schlägt aus verschiedenen Gründen fehl). Beispiel:
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;
wird ausgeführt
db2look -d <db> -e -td @ -ct
generiert die falsche Reihenfolge für den Index und die Einschränkung.
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@
Das Entfernen von -ct funktioniert in diesem einfachen Beispiel, schlägt jedoch in der tatsächlichen Datenbank aufgrund anderer Abhängigkeiten fehl.
Ich stelle mir vor, die Migration auf UTF-8 ist eine recht häufige Aufgabe, daher bin ich neugierig, worauf es ankommt Menschen haben getan. Die zwei möglichen Lösungen, die ich sehe, sind:
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.
Bei beiden gibt es eindeutig Nachteile. Übersehe ich eine triviale Möglichkeit, die Datenbanken zu migrieren?
EDIT: Eine zusätzliche Beobachtung ist, dass eine QL0605W
-Warnung eine QL0605W
-Warnung enthält, solange ein Index keine zusätzlichen Attribute im Vergleich zum implizit erstellten Index enthält wird angehoben. Wenn andererseits zusätzliche Attribute angegeben werden, wird ein SQL0601N
-Fehler ausgelöst. Beispiel:
CREATE UNIQUE INDEX X1 ON T1 (C1, C2) COMPRESS NO INCLUDE NULL KEYS DISALLOW REVERSE SCANS
generiert eine Warnung SQL0605W
, wenn ein ähnlicher Index über die Primärschlüsselanweisung erstellt wird. P. >
Andererseits erzeugt ein Index wie:
CREATE UNIQUE INDEX X2 ON T2 (C1, C2) INCLUDE (C3) CLUSTER COMPRESS NO INCLUDE NULL KEYS ALLOW REVERSE SCANS
einen Fehler SQL0601N
. Ich gehe davon aus, dass dies auf die INCLUDE-Klausel zurückzuführen ist, aber möglicherweise verursacht die CLUSTER-Klausel auch dieses Verhalten.
Kommentare
- Ich verwende häufig db2look – d -a -l -e -o -td “@ “ das hat bei mir funktioniert.
- Danke, aber das gibt Objekte in der falschen Reihenfolge für das aus db in Frage. Ich vermute, dass ein Teil des Problems darauf zurückzuführen ist, dass die Datenbank 2005 erstellt wurde und seitdem regelmäßig Schemaänderungen vorgenommen wurden.
- Setzt den Datenbankkonfigurationsparameter
AUTO_REVAL
umDEFERRED_FORCE
Ihr Problem zu lösen? - @Ian, nicht wirklich. Das hilft nur bei einigen Abhängigkeitsverletzungen. Eigentlich ziehe ich es vor, alles oder nichts zu laufen (
db2 +c -s ...
), damit ich sicher sagen kann, dass alles korrekt neu erstellt wurde.
Antwort
Vor einigen Jahren haben wir unseren DB2 von 9.7 auf 10.5 migriert. Wir haben auch die Datenbank auf neue Hardware verschoben und die Datenkomprimierung implementiert. Aus diesem Grund haben wir beschlossen, die Datenbank von Grund auf neu zu erstellen und die Daten zu exportieren und zu importieren.
Wir haben db2look und db2move verwendet, um die Arbeit zu erledigen. Es gab jedoch keine Möglichkeit, die von db2look erstellte DDL in der richtigen Reihenfolge zu erstellen. Wir mussten das generierte Skript in verschiedene Teile aufteilen, um Tabellen zu erstellen, Trigger zu erstellen, Indizes zu erstellen usw.
Schließlich führen wir die folgenden Schritte aus:
- exportieren Sie das Vorhandene Daten
- Neue Datenbank erstellen
- Pufferpools und Tabellenbereiche erstellen
- Tabellen erstellen
- Primärschlüssel erstellen
- Indizes erstellen
- Ansichten erstellen
- Daten laden
- Reorgs und Runstats ausführen
- gespeicherte Prozeduren, benutzerdefinierte Funktionen und Trigger erstellen
Ich hoffe, es hilft, auch wenn es nicht die Antwort ist, die Sie vielleicht erwartet haben.
Kommentare
- Vielen Dank für Ihre Antwort. Die Situation ist etwas komplizierter (es gibt zum Beispiel Tabellen, die von Funktionen abhängig sind und umgekehrt). Ich ‚ werde wahrscheinlich einen Parser erstellen, der die Ausgabe von db2look in topologischer Reihenfolge mithilfe von Abhängigkeitstabellen sortiert.
Antwort
Grobe Vorstellung davon, wie Datenbankobjekte in der richtigen Reihenfolge abgerufen werden. Das Abhängigkeitsdiagramm ist nicht vollständig, scheint aber meine Anforderungen zu erfüllen.
#!/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))
Jetzt kann x verwendet werden, um Dinge in der richtigen Reihenfolge aus db2look auszuwählen. Ich habe einen einfachen Parser verwendet, der die Ausgabe von db2look
in Listen liest. Durch Schleifen über x und Auswählen der Definition aus dem rechten Bucket kann eine sortierte Ausgabe erzielt werden. Der Parser selbst ist nur eine Reihe von regulären Ausdrücken und nicht besonders interessant. Da die Anweisungen jedoch über mehrere Zeilen verteilt sind, ist es hilfreich, einen stmt-Leser zu haben:
# 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
BEARBEITEN: Ich habe einen Parser unter https://github.com/lelle1234/Db2Utils . Es ist keineswegs vollständig, sondern hat für meine Bedürfnisse gearbeitet.
Dort gibt es auch einen Indexberater, der versucht, einen optimalen Satz von Indizes für eine bestimmte Abfrage und eine Datenbank zu erstellen.
Antwort
Ich habe den folgenden Ansatz verwendet, um das Produktionsschema auf Testserver für Entwickler zu kopieren. Der Trick besteht darin, Fehler während einzelner Läufe zu ignorieren und das Schema am Ende zu vergleichen, um sicherzustellen, dass alles korrekt neu erstellt wird. Ich weiß, dass es kein sauberer Ansatz ist. Ich habe dies gegen Schema mit über 1000 Tabellen, 500 Funktionen mit Abhängigkeiten, Einschränkungen usw. getan. Sie können die Schritte mithilfe eines Shell-Skripts automatisieren. Es erfordert viel weniger Aufwand als das Schreiben und Testen des Parsers.
Schritt 1 Verwenden Sie das Skript, um das Schema in einer bestimmten Reihenfolge vom Produktionsserver zu extrahieren (db2look für Tablespaces zuerst, db2look für Tabellen als nächstes usw.). Die Verwendung einer bestimmten Reihenfolge reduziert die Anzahl der Iterationen für Schritt 2 & 3.
Schritt 2 Führen Sie die Ausgabe von Schritt 1 auf dem Testserver aus.
Schritt 3 Extrahieren Sie das Schema vom Testserver und vergleichen Sie es mit dem Schema vom Produktionsserver.
Schritt 4 Wiederholen Sie die Schritte 2 und 3, bis beide Schemas synchron sind.
Schreibe einen Kommentar