Gebruikt u db2look om een database na te bootsen?
Geplaatst op februari 14, 2021 door adminIk ben bezig met het migreren van enkele databases van iso8859-1 naar utf-8. Een van de databases bevat meer dan 1000 tabellen, heel veel procedures, functies, triggers, beperkingen etc. Ik zou het proces zoveel mogelijk willen automatiseren, aangezien dit meerdere keren zal gebeuren, en voor verschillende instanties van het systeem. Idealiter zou ik het werk willen overdragen aan mijn vrienden Jenkins en Ansible 😉
Mijn plan was om de ddl te genereren met db2look, maar het lukt niet om de “objecten” in de juiste volgorde te genereren. Ik heb geprobeerd om zowel met als zonder de vlag -ct te draaien (mislukt om verschillende redenen) . Bijvoorbeeld:
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;
actief
db2look -d <db> -e -td @ -ct
genereert de verkeerde volgorde voor de index en de beperking.
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@
Het verwijderen van -ct werkt in dit triviale voorbeeld, maar mislukt in de eigenlijke database vanwege andere afhankelijkheden.
Ik stel me voor dat migreren naar UTF-8 een vrij gebruikelijke taak is, dus ik ben nieuwsgierig naar wat p mensen hebben gedaan. De twee mogelijke oplossingen die ik zie zijn:
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.
Het is duidelijk dat er nadelen aan beide zijn, zie ik een of andere triviale manier om de databases te migreren over het hoofd?
BEWERKEN: een aanvullende observatie is dat zolang een index geen extra attributen bevat in vergelijking met de impliciet gecreëerde index door een unieke / primaire sleutelbeperking een QL0605W
waarschuwing wordt verhoogd. Als aan de andere kant extra attributen worden gespecificeerd, wordt een SQL0601N
fout gegenereerd. Voorbeeld:
CREATE UNIQUE INDEX X1 ON T1 (C1, C2) COMPRESS NO INCLUDE NULL KEYS DISALLOW REVERSE SCANS
genereert een waarschuwing SQL0605W
als een vergelijkbare index wordt gemaakt via de instructie van de primaire sleutel.
Aan de andere kant genereert een index zoals:
CREATE UNIQUE INDEX X2 ON T2 (C1, C2) INCLUDE (C3) CLUSTER COMPRESS NO INCLUDE NULL KEYS ALLOW REVERSE SCANS
een fout SQL0601N
. Ik neem aan dat dit komt door de INCLUDE-clausule, maar misschien zal de CLUSTER-clausule dit gedrag ook veroorzaken.
Reacties
Antwoord
Enkele jaren geleden hebben we onze DB2 gemigreerd van 9.7 naar 10.5. We hebben ook de database naar nieuwe hardware verplaatst en datacompressie geïmplementeerd. Daarom hebben we besloten om de database helemaal opnieuw te maken en de gegevens te exporteren en importeren.
We hebben db2look en db2move gebruikt om het werk te doen. Er was echter geen manier om de DDL gemaakt door db2look in de juiste volgorde te krijgen. We moesten het gegenereerde script opsplitsen in verschillende delen voor het maken van tabellen, het maken van triggers, het maken van indexen, enz.
Ten slotte eindigen we met de volgende stappen:
- exporteer het bestaande gegevens
- maak de nieuwe database
- maak bufferpools en tabelruimten
- maak tabellen
- maak primaire sleutels
- maak indexen
- creëer views
- laad data
- run reorgs en runstats
- creëer opgeslagen procedures, door de gebruiker gedefinieerde functies en triggers
Ik hoop dat het helpt, ook al is het niet het antwoord dat u misschien had verwacht.
Reacties
- Bedankt voor je antwoord. De situatie is wat ingewikkelder (er zijn bijvoorbeeld tabellen die afhankelijk zijn van functies en vice versa). Ik ‘ zal waarschijnlijk een parser maken die de uitvoer van db2look in topologische volgorde sorteert met behulp van afhankelijkheidstabellen.
Antwoord
Ruw idee om databaseobjecten in de juiste volgorde te krijgen. De afhankelijkheidsgrafiek is niet compleet, maar lijkt aan mijn behoeften te voldoen.
#!/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))
Nu kan x worden gebruikt om dingen in de juiste volgorde te kiezen uit db2look. Ik heb een triviale parser gebruikt die de uitvoer van db2look
in lijsten leest. Door x te herhalen en de definitie uit de juiste bucket te halen, kan een gesorteerde output worden bereikt. De parser zelf is slechts een stel reguliere expressies en niet bijzonder interessant, maar aangezien de uitspraken over verschillende regels zijn verdeeld, is een stmt-lezer handig om te hebben:
# 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: ik heb een parser op https://github.com/lelle1234/Db2Utils . Het is zeker niet compleet, maar werkte voor mijn behoeften.
Er is daar ook een indexadviseur die probeert een optimale set indexen te bedenken voor een bepaalde zoekopdracht en een database.
Antwoord
Ik heb de volgende benadering gebruikt om het productieschema te kopiëren naar testservers voor ontwikkelaars. De truc is om fouten tijdens individuele runs te negeren en het schema aan het einde te vergelijken om er zeker van te zijn dat alles correct wordt gemaakt. Ik weet dat het geen zuivere benadering is. Ik heb dit gedaan met een schema met meer dan 1000 tabellen, 500 functies met afhankelijkheden, beperkingen, enz. U kunt de stappen automatiseren met behulp van een shell-script. Het vereist veel minder moeite in vergelijking met het schrijven van een parser en het testen ervan.
Stap 1 Gebruik script om het schema uit de productieserver te halen in een specifieke volgorde (eerst db2look voor tabelruimten, daarna db2look voor tabellen, enz.). Het gebruik van een specifieke volgorde vermindert het aantal iteraties voor stap 2 & 3.
Stap 2 Voer de uitvoer uit vanaf stap 1 op testserver
Stap 3 Haal het schema uit de testserver en vergelijk het met het schema van de productieserver.
Stap 4 Herhaal stap 2 en 3, totdat beide schemas synchroon lopen.
AUTO_REVAL
databaseconfiguratieparameter omDEFERRED_FORCE
je probleem op te lossen?db2 +c -s ...
), zodat ik gerust kan zeggen dat alles correct is nagemaakt.