Von Problemen in der Oracle 12c Multitenant Datenbank
Früher war doch alles einfacher, oder? Bis jetzt hat sich wohl der ein oder andere an seine Datenbank angemeldet und im Zweifel über eine Abfrage der v$instance oder der v$database mal schnell gegen gecheckt ob er auch richtig gelandet ist. Seit 12c ist das aber leider nicht mehr so eindeutig. Inzwischen gibt es die Multitenant Option und verbinde ich mich mit einer Pluggable Database, bekomme ich mit meinen althergebrachten Views vielleicht nicht das gewünschte Ergebnis.
Aber warum ist das so ein Problem?
In einer Multitenant Umgebung kann man sich nicht nur direkt anmelden, sondern auch durch ein ALTER SESSION zwischen den verschiedenen Pluggable Datenbanken und dem Root Container hin und her springen. Arbeitet man mit mehreren Sessions und verschiedenen Fenstern, kann man schonmal den Überblick verlieren. Auch für das Scripting kann es hilfreich sein, Änderungen auch auf die richtige PDB anzuwenden und nicht versehentlich auf den Root Container.
Im folgenden Beispiel habe ich eine einfache 12c Multitenant Datenbank mit der CDB, also dem ROOT Container und einer angeschlossenen Pluggable Database (PDB).
CDB = SJW12C01 und PDB = SJWPDB01
Unsere v$instance ist in Sachen PDB leider nicht mehr so hilfreich, auch wenn das Ergebnis vollkommen korrekt ist:
CDB
sqlplus system@SJW12C01 SQL> select instance_name, con_id, version from v$instance; INSTANCE_NAME CON_ID VERSION ---------------- ---------- ----------------- sjw12c01 0 12.1.0.2.0
PDB
sqlplus system@SJWPDB01 SQL> select instance_name, con_id, version from v$instance; INSTANCE_NAME CON_ID VERSION ---------------- ---------- ----------------- sjw12c01 0 12.1.0.2.0
Leider das gleiche Bild mit der v$database Abfrage:
CDB
sqlplus system@SJW12C01 SQL> select name, con_id, db_unique_name from v$database; NAME CON_ID DB_UNIQUE_NAME --------- ---------- ------------------------------ SJW12C01 0 SJW12C01
PDB
sqlplus system@SJWPDB01 SQL> select name, con_id, db_unique_name from v$database; NAME CON_ID DB_UNIQUE_NAME --------- ---------- ------------------------------ SJW12C01 0 SJW12C01
Mit der v$pdbs haben wir eine erste Möglichkeit Abhilfe zu schaffen. Ähnliche Ergebnisse liefert auch ein select * from cdb_pdbs;. Nachfolgend springen wir mit alter session set container von der CDB zur PDB und wieder zurück:
CDB > PDB > CDB
sqlplus system@SJW12C01 SQL> select dbid, con_id, name from v$pdbs; DBID CON_ID NAME ---------- ---------- ------------------------------ 4043975488 2 PDB$SEED 4185832567 3 SJWPDB01 SQL> alter session set container = SJWPDB01; Session wurde geõndert. SQL> select dbid, con_id, name from v$pdbs; DBID CON_ID NAME ---------- ---------- ------------------------------ 4185832567 3 SJWPDB01 SQL> alter session set container = CDB$ROOT; Session wurde geõndert. SQL> select dbid, con_id, name from v$pdbs; DBID CON_ID NAME ---------- ---------- ------------------------------ 4043975488 2 PDB$SEED 4185832567 3 SJWPDB01
Wie man sieht, erhält man in der Container Datenbank Infos über die PDB$SEED. Die SEED Datenbank dient in der Multitenant Datenbank als Vorlage für die Erstellung neuer PDB’s. In einer PDB dagegen bekommt man in jedem Fall nur eine, die eigene PDB angezeigt.
Aber es geht noch besser über USERENV aus der SYS_CONTEXT Funktion heraus:
CDB
sqlplus system@SJW12C01 SQL> select sys_context('USERENV','CON_NAME') CON_NAME, sys_context('USERENV','CON_ID') CON_ID, sys_context('USERENV','DB_NAME') DB_NAME from DUAL; CON_NAME CON_ID DB_NAME ---------- ---------- ---------- CDB$ROOT 1 SJW12C01
PDB
sqlplus system@SJWPDB01 SQL> select sys_context('USERENV','CON_NAME') CON_NAME, sys_context('USERENV','CON_ID') CON_ID, sys_context('USERENV','DB_NAME') DB_NAME from DUAL; CON_NAME CON_ID DB_NAME ---------- ---------- ---------- SJWPDB01 3 SJW12C01
Aufgepasst bei DB_NAME. Hier wird immer der Name der (Root) Container Datenbank zurück gegeben. Die CON_ID ist sicherlich auch schon aufgefallen. Hier nicht irritieren lassen CON_ID 0 steht für die Gesamtheit der Multitenant Datenbank und 1 ist für den Root Container reserviert. CON_ID 2 ist immer die PDB$SEED. Alles ab CON_ID 3 sind Pluggable Databases.
Mit diesem Wissen und etwas DECODE erhält man immer den aktuellen Datenbanknamen und ob man sich auf der CDB oder einer PDB befindet:
CDB
sqlplus system@SJW12C01 SQL> select decode(sys_context('USERENV', 'CON_NAME'),'CDB$ROOT',sys_context('USERENV', 'DB_NAME'),sys_context('USERENV', 'CON_NAME')) DB_NAME, decode(sys_context('USERENV','CON_ID'),1,'CDB','PDB') TYPE from DUAL; DB_NAME TYPE ---------- ---- SJW12C01 CDB
PDB
sqlplus system@SJWPDB01 SQL> select decode(sys_context('USERENV', 'CON_NAME'),'CDB$ROOT',sys_context('USERENV', 'DB_NAME'),sys_context('USERENV', 'CON_NAME')) DB_NAME, decode(sys_context('USERENV','CON_ID'),1,'CDB','PDB') TYPE from DUAL; DB_NAME TYPE ---------- ---- SJWPDB01 PDB
Schneller und einfacher geht es noch mit SQL Plus (leider nur hier), mittels SHOW CON_ID, SHOW CON_NAME. SHOW PDBS dagegen funktioniert nur als SYSDBA. Achten Sie in diesem Beispiel auch auf den connect / as sysdba – durch die Neuanmeldung wechselt die Umgebung von PDB auf CDB. Man sollte sich vom Parameter db_name nicht irritieren lassen.:
CDB > PDB > CDB > PDB
sqlplus system@SJW12C01 SQL> show parameter db_name NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ db_name string SJW12C01 SQL> show con_id CON_ID ------------------------------ 1 SQL> show con_name CON_NAME ------------------------------ CDB$ROOT SQL> alter session set container = SJWPDB01; Session wurde geõndert. SQL> show parameter db_name NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ db_name string SJW12C01 SQL> show con_id CON_ID ------------------------------ 3 SQL> show con_name CON_NAME ------------------------------ SJWPDB01 SQL> conn / as sysdba Connect durchgef³hrt. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 SJWPDB01 READ WRITE NO SQL> show con_name CON_NAME ------------------------------ CDB$ROOT SQL> show con_id CON_ID ------------------------------ 1 SQL> alter session set container = SJWPDB01; Session wurde geõndert. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ---------- ------------------------------ ---------- ---------- 3 SJWPDB01 READ WRITE NO
Hinweis
Seit der Version 12.2 wird bei der Ausgabe von sys_context(‚USERENV‘,’DB_NAME‘) in der CDB$ROOT der Name der Datenbank ausgegeben, innerhalb einer PDB aber der Name der PDB.
Habe soeben die 18c XE installiert und war verzweifelt, weil nichts aus dem von mir gewählten Tutorial klappen wollte.
Jetzt habe ich verstanden, wie das mit der CDB und PDB läuft.
Super Erklärung. Danke.
habe im $ORACLE_HOME/sqlplus/admin/glogin.sql eine Promptänderung eingetragen. Da weiss ich immer , wo ich gerade bin.
Eintrag: set sqlprompt „_user’@‘ _connect_identifier>“
Ergebnis sqlplus sys/xxxxxxxxx@cdb1:
SYS@ cdb1>conn sys/xxxxxxxxxx@pdb11
SYS@ pdb11>
Guter Tipp, danke für den Hinweis
hinter die connect anweisungen sollte schon noch ein “ as sysdba“ stehen.
Hallo Horst,
sorry aber ich sehe nicht, wo der Connect fehlerhaft sein sollte. Da in den meisten Fällen der User „SYSTEM“ genommen wurde, ist hier kein „as sysdba“ notwendig bzw. in der Regel auch gar nicht möglich.