I've described Oracle 12c metadata and object links internals in a previous post. But before that, the first time I investigated on it, I made a wrong assumption because I was looking at AUDIT_ACTIONS which is not correctly implemented. That investigation came from a question on dba-village. And recently Ivica Arsov (@IvicaArsov) has made an interesting comment about AUDIT_ACTIONS object link table, so I'll explain here what is special with it.
AUDIT_ACTIONS
Here is how is defined AUDIT_ACTIONS:
SQL> select object_name,object_type,sharing from dba_objects where object_name in ('DBA_AUDIT_TRAIL','AUDIT_ACTIONS') order by object_name,object_type; OBJECT_NAME OBJECT_TYPE SHARING -------------------- --------------- ------------- AUDIT_ACTIONS SYNONYM METADATA LINK AUDIT_ACTIONS TABLE OBJECT LINK DBA_AUDIT_TRAIL SYNONYM METADATA LINK DBA_AUDIT_TRAIL VIEW METADATA LINKIt's a sharing=object table so you expect that the data is common to all containers. And we will also query a view that reads that table - DBA_AUDIT_TRAIL.
Then let's query the table from CDB$ROOT and from a PDB and check from ROWID if we read the same rows:
SQL> alter session set container=CDB$ROOT; Session altered. SQL> select rowid,action,name,dbms_rowid.rowid_to_absolute_fno(rowid,'SYS','AUDIT_ACTIONS') file_id from AUDIT_ACTIONS where action=3; ROWID ACTION NAME FILE_ID ------------------ ---------- ------- ---------- AAABG7AABAAACo5AAD 3 SELECT 1 SQL> alter session set container=PDB1; Session altered. SQL> select rowid,action,name,dbms_rowid.rowid_to_absolute_fno(rowid,'SYS','AUDIT_ACTIONS') file_id from AUDIT_ACTIONS where action=3; ROWID ACTION NAME FILE_ID ------------------ ---------- ------- ---------- AAABG5AABAAAA3pAAD 3 SELECT 8The rows are not coming from the same file, but from the local SYSTEM tablespace of each container. This is a proof that this OBJECT LINK table is not common at all.
DBA_AUDIT_TRAIL
Now I want to check what happens when we query through the view. I don't have the ROWID so let's update the table in the PDB so that we can distinguish rows coming from CDB$ROOT and from PDB1:
SQL> update AUDIT_ACTIONS set name='select' where action=3; 1 row updated. SQL> select rowid,action,name from AUDIT_ACTIONS where action=3; ROWID ACTION NAME ------------------ ---------- ------- AAABG5AABAAAA3pAAD 3 select SQL> select distinct dbid,action,action_name from DBA_AUDIT_TRAIL; DBID ACTION ACTION_NAME ---------- ---------- ---------------------------- 314687597 3 selectOk. I've changed one 'ACTION_NAME' to lowercase - only in the PDB1. And when I query through the view I see the local row. This definitly prooves that the implementation of AUDIT_ACTIONS is not achieving the goal of multinenant dictionary: store common oracle objects only in CDB$ROOT to avoid duplication and faciliate upgrade. Note that it is not a big problem anyway as it is just a 200 rows table.
DBA_CPOOL_INFO
In order to show the normal behaviour of object links I'll do the same with DBA_CPOOL_INFO which is a view over SYS.CPOOL$. I've described this behaviour previously by creating my own objects but here I'll show how it is used to store the DRCP information which is at CDB level. Here are the involved table and views:
SQL> select object_name,object_type,sharing from dba_objects where object_name in ('CPOOL$','INT$DBA_CPOOL_INFO','DBA_CPOOL_INFO') order by object_name,object_type; OBJECT_NAME OBJECT_TYPE SHARING -------------------- --------------- ------------- CPOOL$ TABLE OBJECT LINK DBA_CPOOL_INFO SYNONYM METADATA LINK DBA_CPOOL_INFO VIEW METADATA LINK INT$DBA_CPOOL_INFO VIEW OBJECT LINKCPOOL$ is defined with sharing=object. An internal view INT$DBA_CPOOL_INFO is defined on it with sharing=object as well. And finally that view is exposed through DBA_CPOOL_INFO. As before, I check the ROWID of CPOOL$ row from CDB$ROOT and PDB1:
SQL> alter session set container=CDB$ROOT; Session altered. SQL> select rowid,minsize,dbms_rowid.rowid_to_absolute_fno(rowid,'SYS','CPOOL$') file_id from SYS.CPOOL$; ROWID MINSIZE FILE_ID ------------------ ---------- ---------- AAABz5AABAAADb5AAA 4 1 SQL> alter session set container=PDB1; Session altered. SQL> select rowid,minsize,dbms_rowid.rowid_to_absolute_fno(rowid,'SYS','CPOOL$') file_id from SYS.CPOOL$; ROWID MINSIZE FILE_ID ------------------ ---------- ---------- AAABz3AABAAABQJAAA 4 8
So this is the same as we have seen before: an OBJECT LINK has its data in each PDB.
But what is different here is the view charing which is sharing=object. Let's query that view after changing the value in PDB1:
SQL> update SYS.CPOOL$ set minsize=0; 1 row updated. SQL> select rowid,minsize,dbms_rowid.rowid_to_absolute_fno(rowid,'SYS','CPOOL$') file_id from SYS.CPOOL$; ROWID MINSIZE FILE_ID ------------------ ---------- ---------- AAABz3AABAAABQJAAA 0 8 SQL> select minsize from INT$DBA_CPOOL_INFO; MINSIZE ---------- 4 SQL> select minsize from DBA_CPOOL_INFO; MINSIZE ---------- 4Now we have a view which will always show the CDB$ROOT rows, even when we are in a PDB container. We still have rows in the PDB containers, but they will not be used. Once again, this defeats the goal of deduplication, but this is a very small table.
AWR tables
The main advantage of multitenant dictionary architecture is with the big tables storing data which is common in the whole CDB, such as the AWR data:
SQL> alter session set container=CDB$ROOT; Session altered. SQL> select con_id,count(*) from containers(WRH$_SQLTEXT) group by con_id; CON_ID COUNT(*) ---------- ---------- 1 5549 SQL> alter session set container=PDB1; Session altered. SQL> select count(*) from WRH$_SQLTEXT; COUNT(*) ---------- 0This information - stored only from CDB$ROOT - is shared in all PDB through the OBJECT LINK view.