Blog Sebastian

Blog Sebastian

sebastian blog ohne logo

Hilfe, wo bin ich? CDB oder PDB … und welche DB überhaupt?

Veröffentlicht: 16. März 2017
Geschrieben von Sebastian Winkler
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

 

 

Sebastian Winkler

Twitter sjw1011

CarajanDB GmbH

Siemensstr. 25  50374 Erftstadt

Fon: +49 (2235) 170 91 83

Fax: +49 (2235) 170 79 78

Mail: info@carajandb.com

 

carajan-db-logo