Oracle Multitenant was introduced in 12c and is now the default deployment model. Despite broad adoption, the internal mechanics of how CDBs and PDBs share and isolate resources are frequently misunderstood. This article is for architects designing multitenant deployments who need to reason about performance isolation, resource governance, and operational boundaries.
CDB vs Non-CDB: The Core Difference
In a non-CDB, the database owns the entire Oracle instance. In a CDB:
- The CDB root (CDB$ROOT) is the container that owns the instance (SGA, background processes, redo logs, undo tablespace if using local undo mode, control file).
- PDBs are pluggable databases — each has its own data dictionary, tablespaces, users, and objects — but they share the instance.
This sharing is the source of both efficiency (lower per-database overhead) and the isolation challenge architects must manage.
-- Identify whether a database is a CDB
SELECT cdb, con_id, name FROM v$database;
CDB CON_ID NAME
----- ------- ----
YES 1 CDB1
Memory Architecture in Multitenant
The SGA is shared across all PDBs. The buffer cache, shared pool, large pool, and redo buffer are not per-PDB — they are CDB-level resources. This means:
- A large PDB with many parsed SQL statements consumes shared pool space from the CDB’s shared pool.
- A PDB with a large working set can thrash the buffer cache for other PDBs.
PGA and SGA Per-PDB Controls (19c+)
Oracle 19c introduced per-PDB memory limits to address this:
-- Set SGA limit for a specific PDB (caps the PDB's buffer cache and shared pool usage)
ALTER PLUGGABLE DATABASE pdb_analytics SET SGA_MIN_SIZE = 4G, SGA_TARGET = 8G;
ALTER PLUGGABLE DATABASE pdb_oltp SET SGA_MIN_SIZE = 2G, SGA_TARGET = 4G;
-- PGA limit per PDB
ALTER PLUGGABLE DATABASE pdb_analytics SET PGA_AGGREGATE_LIMIT = 4G;
Without these limits, a “noisy neighbour” PDB can evict another PDB’s data from the shared buffer cache, causing cache thrashing across the CDB.
Undo and Redo in Multitenant
Local Undo Mode (Recommended)
Each PDB has its own undo tablespace. This is the recommended configuration:
-- Check undo mode
SELECT property_name, property_value
FROM database_properties
WHERE property_name = 'LOCAL_UNDO_ENABLED';
Local undo enables independent flashback and point-in-time recovery per PDB. Without it (shared undo), flashback one PDB affects all PDBs sharing the undo tablespace.
Redo: Shared at CDB Level
Redo logs are always CDB-level. All PDBs write to the same online redo logs. This means:
- High redo generation from one PDB directly impacts commit latency for all PDBs (log file sync waits).
- IORM or Resource Manager does not throttle redo on a per-PDB basis.
- For PDBs with dramatically different redo rates, consider separate CDBs.
CDB Resource Manager for CPU and I/O Governance
The CDB Resource Manager governs CPU (and optionally I/O via Exadata IORM integration) across PDBs within a CDB.
-- Create a CDB-level resource plan
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PENDING_AREA();
DBMS_RESOURCE_MANAGER.CREATE_CDB_PLAN(
plan => 'PROD_CDB_PLAN',
comment => 'Production CDB resource plan'
);
-- OLTP PDB: highest CPU priority
DBMS_RESOURCE_MANAGER.CREATE_CDB_PLAN_DIRECTIVE(
plan => 'PROD_CDB_PLAN',
pluggable_database => 'PDB_OLTP',
shares => 8,
utilization_limit => 80, -- max 80% of CDB CPU
parallel_server_limit => 40 -- max 40% of parallel servers
);
-- Analytics PDB: lower priority, more parallel headroom
DBMS_RESOURCE_MANAGER.CREATE_CDB_PLAN_DIRECTIVE(
plan => 'PROD_CDB_PLAN',
pluggable_database => 'PDB_ANALYTICS',
shares => 2,
utilization_limit => 60,
parallel_server_limit => 80
);
-- Default directive for any unspecified PDB
DBMS_RESOURCE_MANAGER.UPDATE_CDB_DEFAULT_DIRECTIVE(
plan => 'PROD_CDB_PLAN',
new_shares => 1,
new_utilization_limit => 20
);
DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA();
DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA();
END;
/
-- Activate the CDB plan
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'PROD_CDB_PLAN' SCOPE=BOTH;
PDB Cloning: Thin Clones and Full Clones
PDB cloning is one of the most powerful operational features of Multitenant.
Full Clone
-- Clone PDB_PROD to create a test/dev copy
CREATE PLUGGABLE DATABASE PDB_TEST FROM PDB_PROD;
This creates a complete copy. For large PDBs, use the SNAPSHOT COPY option to create a thin clone backed by OS-level copy-on-write (ASM sparse disk groups or NFS with DBCLONEDB).
Thin Clone with ASM Sparse Groups (Exadata)
On Exadata with the +SPARSE disk group, PDB clones share the parent’s data blocks until modified:
-- Create a thin clone (storage-efficient, instant)
CREATE PLUGGABLE DATABASE PDB_DEV FROM PDB_PROD
SNAPSHOT COPY;
The thin clone has an independent data dictionary and can be modified without affecting the source. Only changed blocks are stored in +SPARSE — a 2 TB production PDB can have a 10 GB thin clone.
Refreshable PDB Clones
For keeping test environments synchronised with production:
-- Create a refreshable clone (periodically synced from source)
CREATE PLUGGABLE DATABASE PDB_TEST_REFRESH
FROM PDB_PROD@PROD_DBLINK
REFRESH MODE MANUAL;
-- Refresh on demand
ALTER PLUGGABLE DATABASE PDB_TEST_REFRESH REFRESH;
PDB Relocation: Zero-Downtime Movement Between CDBs
Relocate a PDB from one CDB to another with near-zero downtime:
-- On the target CDB: pull the PDB from the source CDB
-- (requires CDB$ROOT-to-CDB$ROOT database link)
CREATE PLUGGABLE DATABASE PDB_PROD
FROM PDB_PROD@SOURCE_CDB_LINK
RELOCATE
AVAILABILITY MAX; -- minimize downtime using redo shipping during relocation
AVAILABILITY MAX uses online redo shipping to keep the target in sync during the copy phase. The final cutover (a brief open-mode switch) takes seconds, not hours.
Monitoring PDB-Level Resource Usage
-- CPU usage per PDB from Resource Manager metrics
SELECT con_id,
consumer_group_name,
cpu_consumed_time,
cpu_wait_time,
active_parallel_stmts,
queued_parallel_stmts
FROM v$rsrcpdbmetric_history
WHERE con_id > 2 -- exclude CDB$ROOT (1) and PDB$SEED (2)
ORDER BY cpu_consumed_time DESC;
-- Buffer cache usage per PDB (from V$DB_CACHE_ADVICE / V$BUFFER_POOL)
SELECT con_id,
ROUND(SUM(db_block_gets + consistent_gets) / 1e6, 1) AS logical_reads_M
FROM v$segment_statistics
WHERE statistic_name = 'logical reads'
GROUP BY con_id
ORDER BY logical_reads_M DESC;
Key Design Decisions for Multitenant Architects
- How many PDBs per CDB?: Oracle supports up to 4096 PDBs per CDB. Practically, the right number is determined by CPU, memory, and redo rate requirements. Avoid co-locating PDBs with radically different redo rates.
- Local undo: Always enable local undo mode. The operational benefits (independent PDB flashback, Point-in-Time Recovery) outweigh any marginal overhead.
- PDB memory limits (19c+): Always set
SGA_MIN_SIZEandSGA_TARGETfor PDBs in production CDBs to prevent noisy-neighbour buffer cache eviction. - CDB Resource Manager: Mandatory for any production CDB with more than one PDB. Without it, one PDB can consume 100% of CPU, starving others.
- Separate CDBs for different SLAs: PDBs with zero-tolerance SLAs should not share a CDB with batch/analytics PDBs, regardless of Resource Manager configuration.