Diferença e significado das colunas CDB_ID e PDB_ID em um ambiente MULTI-TENANT
Recentemente, um colega num dos grupos de discussão que frequento estava com dúvidas sobre porque existem colunas CON_ID e PDB_ID nas views do sistema, quando e como usar cada uma delas. O objetivo deste artigo é esclarecer os conceitos envolvidos e tentar indicar quando e como / para que as usar.
Quando temos um ambiente multi-tenant, nós temos um database CDB (que seria o ‘database de controle’, database “MASTER” se vc quiser fazer um paralelo com SQL SERVER, ie, um database em princípio dedicado a gerenciar os outros databases). E temos N PDBs (PDBs= Pluggable Databases, são os databases a conter os dados dos usuários finais, databases esses gerenciados/controlados pelo database CDB/MASTER, e que inclusive tem esse nome de PLUGGABLE porque podem ser desplugados de um CDB e plugados em outro)….
Então, a PRIMEIRA coisa que você TEM que saber é que pra poder obter detalhes sobre PDBs em princípio você ** TEM ** que estar conectado no banco CDB : é ELE que conhece, é ELE quem ‘controla’ os PDBs todos…. Veja só:
Estou conectado no database CDB:
SYSTEM@xe>select cdb, name from v$database; CDB NAME --- ---- YES XE 1 linha selecionada. SYSTEM@xe>
Consigo ver info sobre TODOS os PDBs controlados/gerenciados pelo CDB :
SYSTEM@xe>select PDB_ID, PDB_NAME FROM CDB_PDBS ORDER BY 1; PDB_ID PDB_NAME ---------- ----------- 2 PDB$SEED 3 XEPDB1 2 linhas selecionadas. SYSTEM@xe>
(Esse PDB$SEED é um PDB “interno”, usado como um ‘modelo’, um ‘template’ quando você vai criar um database PDB, desconsidere-o de momento)…
Muito bem. Já se estiver conectado num PDB, ** óbvio ** que ele não tem “permissão” pra enxergar os outros PDBs :
SYSTEM@xepdb1>select PDB_ID, PDB_NAME FROM CDB_PDBS; PDB_ID PDB_NAME ---------- -------- 3 XEPDB1 1 linha selecionada. SYSTEM@xepdb1>
Esse é o primeiro ponto que eu TENHO que indicar, se você for administrar um ambiente MULTI-TENANT tenha CERTEZA que teus scripts gerais que desejam consultar dados gerais estão rodando no banco CDB , okdoc ??
Muito bem, agora vamos falar de CONTAINERS. Pense no CONTAINER como uma área Lógica, aonde são mantidos dados sobre os databases – e o próprio database CDB , sendo um database, tem um Container a que se refere.E a cada vez que um PDB é criado, um Container relacionado com ele é criado também:
SYSTEM@xe>select con_id, name from v$containers order by 1; CON_ID NAME ---------- ----------- 1 CDB$ROOT 2 PDB$SEED 3 XEPDB1 3 linhas selecionadas. SYSTEM@xe>
Vamos checar os PDBs controlados por este banco CDB:
SYSTEM@xe>select PDB_ID, PDB_NAME, CON_ID FROM CDB_PDBS order by 1; PDB_ID PDB_NAME CON_ID ---------- ----------- ---------- 2 PDB$SEED 2 3 XEPDB1 3 2 linhas selecionadas. SYSTEM@xe>
Se eu criar um novo PDB, automagicamente um novo CONTAINER será registrado:
SYSTEM@xe>create pluggable database "BOOKSTORE" 2 admin user "BOOKSTOREADMIN" 3 identified by "BOOKSTOREADMIN" 4 file_name_convert = ('d:\app\oracle\product\XE\18.0.0\oradata\XE\pdbseed\', 'd:\app\oracle\product\XE\18.0.0\oradata\XE\bookstore\'); Banco de dados plugável criado. SYSTEM@xe>select PDB_ID, PDB_NAME FROM CDB_PDBS; SYSTEM@xe>select con_id, name from v$containers order by 1; CON_ID NAME ---------- ----------- 1 CDB$ROOT 2 PDB$SEED 3 XEPDB1 4 BOOKSTORE 4 linhas selecionadas.
E taí o novo PDB também registrado:
SYSTEM@xe>select PDB_ID, PDB_NAME, CON_ID FROM CDB_PDBS order by 1; PDB_ID PDB_NAME CON_ID ---------- ----------- ---------- 2 PDB$SEED 2 3 XEPDB1 3 4 BOOKSTORE 4 3 linhas selecionadas. SYSTEM@xe>
Vou aproveitar e já ABRIR o novo PDB também:
SYS@xe>alter pluggable database "BOOKSTORE" open read write; Banco de dados plugável alterado. SYS@xe>
Muito bem. Voltando à lista de PDBs e CONTAINERS acima, veja que o CONTAINER 1 (o CDB$ROOT) não aparece na view que lista os PDBs porque NÂO se relaciona a um PDB mas sim ao database CDB….
Agora SIM, chegamos no ponto do artigo que é o porquê de algumas views do sistema conterem CON_ID e outras conterem PDB_ID. CON_ID vai ser preenchido para objetos que TANTO podem estar em databases CDB quanto em PDB. Por exemplo, tablespaces.
SYSTEM@xe>desc CDB_TABLESPACES Nome Nulo? Tipo ----------------------------------- -------- ----------------- TABLESPACE_NAME NOT NULL VARCHAR2(30) BLOCK_SIZE NOT NULL NUMBER INITIAL_EXTENT NUMBER NEXT_EXTENT NUMBER MIN_EXTENTS NOT NULL NUMBER MAX_EXTENTS NUMBER MAX_SIZE NUMBER PCT_INCREASE NUMBER MIN_EXTLEN NUMBER STATUS VARCHAR2(9) CONTENTS VARCHAR2(21) LOGGING VARCHAR2(9) FORCE_LOGGING VARCHAR2(3) EXTENT_MANAGEMENT VARCHAR2(10) ALLOCATION_TYPE VARCHAR2(9) PLUGGED_IN VARCHAR2(3) SEGMENT_SPACE_MANAGEMENT VARCHAR2(6) DEF_TAB_COMPRESSION VARCHAR2(8) RETENTION VARCHAR2(11) BIGFILE VARCHAR2(3) PREDICATE_EVALUATION VARCHAR2(7) ENCRYPTED VARCHAR2(3) COMPRESS_FOR VARCHAR2(30) DEF_INMEMORY VARCHAR2(8) DEF_INMEMORY_PRIORITY VARCHAR2(8) DEF_INMEMORY_DISTRIBUTE VARCHAR2(15) DEF_INMEMORY_COMPRESSION VARCHAR2(17) DEF_INMEMORY_DUPLICATE VARCHAR2(13) SHARED VARCHAR2(13) DEF_INDEX_COMPRESSION VARCHAR2(8) INDEX_COMPRESS_FOR VARCHAR2(13) DEF_CELLMEMORY VARCHAR2(14) DEF_INMEMORY_SERVICE VARCHAR2(12) DEF_INMEMORY_SERVICE_NAME VARCHAR2(1000) LOST_WRITE_PROTECT VARCHAR2(7) CHUNK_TABLESPACE VARCHAR2(1) CON_ID NUMBER SYSTEM@xe>
Em views que se referem à PDBs, vou ter o PDB_ID:
SYSTEM@xe>desc cdb_pdbs
Nome Nulo? Tipo
----------------------------------------- -------- --------------
PDB_ID NOT NULL NUMBER
PDB_NAME NOT NULL VARCHAR2(128)
DBID NOT NULL NUMBER
CON_UID NOT NULL NUMBER
GUID RAW(16)
STATUS VARCHAR2(10)
CREATION_SCN NUMBER
VSN NUMBER
LOGGING VARCHAR2(9)
FORCE_LOGGING VARCHAR2(39)
FORCE_NOLOGGING VARCHAR2(3)
APPLICATION_ROOT VARCHAR2(3)
APPLICATION_PDB VARCHAR2(3)
APPLICATION_SEED VARCHAR2(3)
APPLICATION_ROOT_CON_ID NUMBER
IS_PROXY_PDB VARCHAR2(3)
CON_ID NOT NULL NUMBER
UPGRADE_PRIORITY NUMBER
APPLICATION_CLONE VARCHAR2(3)
FOREIGN_CDB_DBID NUMBER
UNPLUG_SCN NUMBER
FOREIGN_PDB_ID NUMBER
CREATION_TIME NOT NULL DATE
REFRESH_MODE VARCHAR2(6)
REFRESH_INTERVAL NUMBER
TEMPLATE VARCHAR2(3)
LAST_REFRESH_SCN NUMBER
TENANT_ID VARCHAR2(255)
SNAPSHOT_MODE VARCHAR2(6)
SNAPSHOT_INTERVAL NUMBER
SYSTEM@xe>
Já que não tenho PDB_ID, tenho que usar CON_ID para consultar as tablespaces na view:
SYSTEM@xe>select distinct CON_ID from CDB_TABLESPACES;
CON_ID
----------
1
3
4
3 linhas selecionadas.
SYSTEM@xe>
Novamente, o Container 1 se refere a um database que não É PDB, então esse CON_ID = 1 não estará contido nas views que se referem à PDBs, como por exemplo a CDB_PDBS. Assim sendo, tenho que fazer um OUTER JOIN se eu quiser mostrar as tablespaces TODAS existentes no ambiente e (quando for uma tablespace referente à PDB) mostrar o nome do PDB:
SYSTEM@xe>select A.CON_ID, B.PDB_NAME, A.TABLESPACE_NAME from CDB_TABLESPACES A, CDB_PDBS B 2 WHERE A.CON_ID = B.PDB_ID (+) 3 order by 1,3; CON_ID PDB_NAME TABLESPACE_NAME ---------- ----------- ------------------------------ 1 SYSAUX 1 SYSTEM 1 TEMP 1 UNDOTBS1 1 USERS 3 XEPDB1 SYSAUX 3 XEPDB1 SYSTEM 3 XEPDB1 TEMP 3 XEPDB1 UNDOTBS1 3 XEPDB1 USERS 4 BOOKSTORE SYSAUX 4 BOOKSTORE SYSTEM 4 BOOKSTORE TEMP 4 BOOKSTORE UNDOTBS1 14 linhas selecionadas. SYSTEM@xe>
Ou seja, a resposta final do artigo é: Nem todas as views do sistema ORACLE num banco CDB possuem PDB_ID porque nem todas se relacionam à PDBs, E caso haja a necessidade de joinear uma view com info de PDB contra uma sem (como foi o caso acima) pode se usar CON_ID…
Para finalizar, três observações:
1. Antes de mais nada, eu tenho que lembrar que a opção de MULTI-TENANT (ie, ter múltiplos databases ‘controlados’ por um database ‘mestre’ e com um só conjunto de processos principais atendendo a todos) foi introduzida na versão 12.1 do RDBMS Oracle, na forma mais simples,que foi a referenciada aqui no artigo. Na versão 12.2 em diante foi INTRODUZIDA a funcionalidade de Application Containers, que é um elemento lógico de controle ADICIONAL a mais para levar em conta.
Os interessados podem se aprofundar lendo este link e a série de artigos sobre Oracle Multi-tenant.
2. A numeração constante na coluna CON_ID ** não é ** aleatória/desprovida de significado. A documentação da Oracle já nos diz:
Each container data object contains a CON_ID column that identifies the container for each row returned.
E também:
Table 19-1 describes the meanings of the values in the CON_ID column.
Table 19-1 CON_ID Column in Container Data Objects
Value in CON_ID Column Description
0 The data pertains to the entire CDB
1 The data pertains to the CDB root
2 The data pertains to the PDB seed
3 – 4,098 The data pertains to a PDB, an application root, or an application PDB
Ou seja, CON_ID é o identificador DO CONTAINER ao qual o PDB está relacionado, os Containers 0, 1 e 2 são ‘reservados’, de uso interno, possuem significado diferenciado nas views do sistema…
3. Não está relacionado com o tema do Artigo, mas há o conceito de CURRENT CONTAINER – mudando o CONTAINER ao qual você está conectado, você passa a enxergar os dados como se estivesse conectado ao database relacionado com o novo CONTAINER:
SYSTEM@xe>alter session set CONTAINER=XEPDB1;
Sessão alterada.
Pronto. Passo a enxergar os dados como se tivesse conectado ao database XEPDB1, que se relaciona com o container XEPDB1:
SYSTEM@xe>select con_id, name from v$containers;
CON_ID NAME
---------- -----------
3 XEPDB1
1 linha selecionada.
SYSTEM@xe>select PDB_ID, PDB_NAME FROM CDB_PDBS ORDER BY 1;
PDB_ID PDB_NAME
---------- -----------
3 XEPDB1
1 linha selecionada.
SYSTEM@xe>
=> Obviamente, só pode fazer isso um usuário Autorizado/permissionado…
Abraços

Profissional atuante há 31 anos na área de TI, dos quais 25 anos dedicados à tecnologia Oracle®, capacitado em Tuning, Instalação, Migração, Backup, Segurança e troubleshooting no RBDMS Oracle, bem como desenvolvimento e programação em PL/SQL, Java, shell scripting C, Oracle Forms e Oracle Reports.
Detentor de Qualificações de DBA Sênior, Analista e Desenvolvedor obtidas via atuação em empresas nas áreas de Finanças, Produção Industrial, Comércio e outras, Certificado como Oracle Database 11g Certified Implementation Specialist, Oracle Certificate Associate (OCA) 11g, IBM Certified Database Associate – DB2 10 Fundamentals, IBM Information Management DB2 10 Technical Professional v3 , IBM InfoSphere Guardium Technical Security Professional v1.
Atuação eventual (desde Out/95) como Instrutor Oracle em PL/SQL, Tuning e programação em Oracle Forms/Reports.