oracle_multitenant_overview

This is an old revision of the document!


Multitenancy is a new concept in Oracle 12c. The basis of it is that, you can separate the application data from the system data. Up to and including 11g, all the data in the database was residing in the same dimension as the system data or any other data for that matter. Data related to different application, were in the same tablespaces or even managed by the same user. Well, from 12c, all this can go under the table, now you can have many databases PDBs (pluggable databases), inside one big database, the root container. There are even more possibilities like application containers and so on, but we will see that later.

With the multi-tenancy, we have a:

  • root container - Where the system data resides. Also you can choose if you want the UNDO tablespace in the root to be used for all PDBs, or each PDB to have its own undo, SYSTEM and SYSAUX tablespace, making it completely independent from the root container.
  • Application Container - Container which consist of 1 or many PDBs which host a specific application. We are able to assign versions and name to such container, furthermore we can initiate installation and upgrade modes.

Firstly, we need to create our container. From 12c, we can create a database to be either as it always has been, a normal database, OR we can create it to allow other databases as well. So it will be a container, let's see how we can do both:

Actually, the creation of a normal database isn't that hard, you can just type:

Create simple database

SQL> Create database;

Simply that, will create us a normal database, well after that you will have to run the catproc and the catalog scripts, but you get the gist.

To create a container, database we NEED to allow it to have PLUGGABLE databases, as follows:

Create CDB

SQL> CREATE DATABASE CDB1 ENABLE PLUGGABLE DATABASE SEED FILE_NAME_CONVERT = ('/loc1/data','/loc2/data');

That will create us a container database called CDB1 and a SEED, after that you will have to run script:

@$ORACLE_HOME/rdbms/admin/catcdb.sql

But other than that, all will be ok. So we have a container, big deal, what then. Well, now we can create PLUGGABLE databases as follows:

As I said before, pluggable databases, are totally separate databases from one another. Imagine it having many databases (PDBs) within one big database (CDB). These PDBs, can have separate user totally individual from each other. So let's see how it is done:

Create PDB

CREATE PLUGGABLE DATABASE pdb2 ADMIN USER pdb_adm IDENTIFIED BY Password1
  FILE_NAME_CONVERT=('/u01/app/oracle/oradata/cdb1/pdbseed/','/u01/app/oracle/oradata/cdb1/pdb2/');

You can use either:

  • FILE_NAME_CONVERT, or
  • CREATE_FILE_DEST, or
  • PDB_FILE_NAME_CONVERT

Either in the session level or on the CREATE statement, up to you, the result will be the same.

Once created, you can list all PDBs in a certain CDB as follows:

List PDBs

COLUMN pdb_name FORMAT A20

SELECT pdb_name, status
FROM   dba_pdbs
ORDER BY pdb_name;

PDB_NAME	     STATUS
-------------------- -------------
PDB$SEED	     NORMAL
PDB1		     NORMAL
PDB2		     NEW
PDB3		     NEW

COLUMN name FORMAT A20

SELECT name, open_mode
FROM   v$pdbs
ORDER BY name;

NAME			       OPEN_MODE
------------------------------ ----------
PDB$SEED		       READ ONLY
PDB1			       MOUNTED
PDB2			       MOUNTED
PDB3			       MOUNTED

Remember, 1 PDB can be in only 1 ROOT$CDB, but 1 CDB can have many PDBs. Furthermore, from 12.2, we have also applicational containers, which are containers within the CDB, but we will speak about them in a second.

We can perform several actions with a PDB:

  • OPEN
  • Plug & Unplig
  • Close
  • Restore / Recover

After we create a CDB, we need to open it, as follows:

Open PDB

SQL> ALTER PLUGGABLE DATABASE pdb2 OPEN;

That command, will open us a database and it will become available to the users. We can also close a pluggable database as follows:

Close PDB

ALTER PLUGGABLE DATABASE pdb2 CLOSE IMMEDIATE;

In 12.1 we could unplug a PDB into .xml file and the migration of the PDB, would be the migration of that XML file AND the relevant database files. From 12.2 we can also unplug the PDB into a .pdb archive file, which contains information about the PDB AND the relevant database files. That will ease our migration.

Unplug to .pdb file

export ORAENV_ASK=NO
export ORACLE_SID=cdb3
. oraenv
export ORAENV_ASK=YES

sqlplus / as sysdba
ALTER PLUGGABLE DATABASE pdb5 CLOSE;
ALTER PLUGGABLE DATABASE pdb5 UNPLUG INTO '/u01/pdb5.pdb';

That assumes, you are using OMF file. The resulting file contains all the necessary data:

List .pdb file

HOST ls -al /u01/pdb5.pdb
-rw-r--r--. 1 oracle oinstall 161702502 Jan  7 21:01 /u01/pdb5.pdb

SQL>

To plug a database, we need the file from above and we need to verify the compatibility as follows:

Plug a PDB

SET SERVEROUTPUT ON
DECLARE
  l_result BOOLEAN;
BEGIN
  l_result := DBMS_PDB.check_plug_compatibility(
                pdb_descr_file => '/u01/pdb5.pdb',
                pdb_name       => 'pdb5');

  IF l_result THEN
    DBMS_OUTPUT.PUT_LINE('compatible');
  ELSE
    DBMS_OUTPUT.PUT_LINE('incompatible');
  END IF;
END;
/
compatible

PL/SQL procedure successfully completed.

SQL>

Create a PDB using the source file

Then we can create a PDB using the .pdb file as follows:

Plug-in PDB

CREATE PLUGGABLE DATABASE pdb5 USING '/u01/pdb5.pdb';

ALTER PLUGGABLE DATABASE pdb5 OPEN READ WRITE;

SELECT name, open_mode
FROM   v$pdbs
ORDER BY name;

NAME			       OPEN_MODE
------------------------------ ----------
PDB$SEED		       READ ONLY
PDB5			       READ WRITE

SQL>

We can clone a PDB as follows:

Cloning a PDB

-- Setting the source to read-only is not necessary for Oracle 12cR2 with local undo, if you use 12.1 or 12.2 without local undo, it is needed:
ALTER PLUGGABLE DATABASE pdb3 CLOSE;
ALTER PLUGGABLE DATABASE pdb3 OPEN READ ONLY;



CREATE PLUGGABLE DATABASE pdb4 FROM pdb3
  FILE_NAME_CONVERT=('/u01/app/oracle/oradata/cdb1/pdb3/','/u01/app/oracle/oradata/cdb1/pdb4/');

ALTER PLUGGABLE DATABASE pdb4 OPEN READ WRITE;



-- Switch the source PDB back to read/write if you made it read-only.
ALTER PLUGGABLE DATABASE pdb3 CLOSE;
ALTER PLUGGABLE DATABASE pdb3 OPEN READ WRITE;

For that feature, you need to be at least: 12.1.0.2, there is a big with 12.1.0.1. Furthermore, there are two varieties of that procedure.

  • Clone from PDB within other CDB
  • Clone a non-CDB

For both, there are the following pre-requisites:

Pre-requisites

  • The user in the local database must have the CREATE PLUGGABLE DATABASE privilege in the root container.
  • The remote database (PDB or non-CDB) must be open in read-only mode.
  • The local database must have a database link to the remote database. If the remote database is a PDB, the database link can point to the remote CDB using a common user, or the PDB using a local or common user.
  • The user in the remote database that the database link connects to must have the CREATE PLUGGABLE DATABASE privilege.
  • The local and remote databases must have the same endianness, options installed and character sets.
  • If the remote database uses Transparent Data Encryption (TDE) the local CDB must be configured appropriately before attempting the clone. If not you will be left with a new PDB that will only open in restricted mode.
  • The default tablespaces for each common user in the remote PDB *must* exist in local CDB. If this is not true, create the missing tablespaces in the root container of the local PDB. If you don't do this your new PDB will only be able to open in restricted mode (Bug 19174942).
  • When cloning from a non-CDB, both the the local and remote databases must using version 12.1.0.2 or higher.

Clone from a PDB in another CDB

As explained, we need to create a user and open the remote PDB in read only, and create Link in the local one:

On remote

Create a user on remote

export ORAENV_ASK=NO
export ORACLE_SID=cdb3
. oraenv
export ORAENV_ASK=YES

sqlplus / as sysdba

ALTER SESSION SET CONTAINER=pdb5;

CREATE USER remote_clone_user IDENTIFIED BY remote_clone_user;
GRANT CREATE SESSION, CREATE PLUGGABLE DATABASE TO remote_clone_user;

CONN / AS SYSDBA
ALTER PLUGGABLE DATABASE pdb5 CLOSE;
ALTER PLUGGABLE DATABASE pdb5 OPEN READ ONLY;
EXIT;

Then we can move to the local machine and create the link:

On local

Create link

###Edit local tnsnames.ora
PDB5 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = ol7-121.localdomain)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = pdb5)
    )
  )
  
export ORAENV_ASK=NO
export ORACLE_SID=cdb1
. oraenv
export ORAENV_ASK=YES

sqlplus / as sysdba

CREATE DATABASE LINK clone_link
  CONNECT TO remote_clone_user IDENTIFIED BY remote_clone_user USING 'pdb5';

-- Test link.
DESC user_tables@clone_link

CREATE PLUGGABLE DATABASE pdb5new FROM pdb5@clone_link;

Pluggable database created.

SQL>

SELECT name, open_mode FROM v$pdbs WHERE name = 'PDB5NEW';

NAME                           OPEN_MODE
------------------------------ ----------
PDB5NEW                        MOUNTED

SQL>

ALTER PLUGGABLE DATABASE pdb5new OPEN;

SELECT name, open_mode FROM v$pdbs WHERE name = 'PDB5NEW';

NAME                           OPEN_MODE
------------------------------ ----------
PDB5NEW                        READ WRITE

SQL>

Non-CDB in this case, refers to normal database, pre 12c So let's see how it will be done. As before we need to create a user and bring the whole database in read only mode:

On remote

<code:bash|Create user and enable read-only> export ORAENV_ASK=NO export ORACLE_SID=db12c . oraenv export ORAENV_ASK=YES

sqlplus / as sysdba

CREATE USER remote_clone_user IDENTIFIED BY remote_clone_user; GRANT CREATE SESSION, CREATE PLUGGABLE DATABASE TO remote_clone_user;

SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE OPEN READ ONLY; EXIT; </Code>

Then on the local we have to do the same as before:

On local

Create DB Link

DB12C =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = ol7-121.localdomain)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = db12c)
    )
  )
  
export ORAENV_ASK=NO
export ORACLE_SID=cdb1
. oraenv
export ORAENV_ASK=YES

sqlplus / as sysdba

CREATE DATABASE LINK clone_link
  CONNECT TO remote_clone_user IDENTIFIED BY remote_clone_user USING 'db12c';

-- Test link.
DESC user_tables@clone_link

Then we can create the PDBs as follows:

Create the PDB

CREATE PLUGGABLE DATABASE db12cpdb FROM NON$CDB@clone_link;

Pluggable database created.

SQL>

SELECT name, open_mode FROM v$pdbs WHERE name = 'DB12CPDB';

NAME                           OPEN_MODE
------------------------------ ----------
DB12CPDB                       MOUNTED

SQL>
ALTER SESSION SET CONTAINER=db12cpdb;

@$ORACLE_HOME/rdbms/admin/noncdb_to_pdb.sql

ALTER PLUGGABLE DATABASE db12cpdb OPEN;

SELECT name, open_mode FROM v$pdbs WHERE name = 'DB12CPDB';

NAME                           OPEN_MODE
------------------------------ ----------
DB12CPDB                       READ WRITE

SQL>

REMEMBER, as the cloned DB wasn't a PDB, we need to run the noncdb_to_pdb.sql.

There is however one BIG flow in that procedure. The problem is that we need the database (non-cdb) or even PDB to be in read-only mode. That pretty much kills all the desire to perform the procedure as the downtime would be too much for production. Because of that from 12.2 we can do a hot clone, which eliminates that prerequisites :)

So let's see how it is done:

Prerequisites

Prerequisites

  * The user in the local database must have the CREATE PLUGGABLE DATABASE privilege in the root container.
  * The remote CDB must use local undo mode. Without this you must open the remote PDB or non-CDB in read-only mode.
  * The remote database should be in archivelog mode. Without this you must open the remote PDB or non-CDB in read-only mode.
  * The local database must have a database link to the remote database. If the remote database is a PDB, the database link can point to the remote CDB using a common user, the PDB or an application container using a local or common user.
  * The user in the remote database that the database link connects to must have the CREATE PLUGGABLE DATABASE privilege.
  * The local and remote databases must have the same endianness.
  * The local and remote databases must either have the same options installed, or the remote database must have a subset of those present on the local database.
  * If the character set of the local CDB is AL32UTF8, the remote database can be any character set. If the local CDB does not use AL32UTF8, the character sets of the remote and local databases much match.
  * If the remote database uses Transparent Data Encryption (TDE) the local CDB must be configured appropriately before attempting the clone. If not you will be left with a new PDB that will only open in restricted mode.
  * Bug 19174942 is marked as fixed in 12.2. I can't confirm this, so just in case I'll leave this here, but it should no longer be the case. The default tablespaces for each common user in the remote CDB *must* exist in local CDB. If this is not true, create the missing tablespaces in the root container of the local PDB. If you don't do this your new PDB will only be able to open in restricted mode (Bug 19174942).
  * When cloning from a non-CDB, both the the local and remote databases must using version 12.1.0.2 or higher.
  * In the examples below I have three databases running on the same virtual machine, but they could be running on separate physical or virtual servers.

cdb1 : The local database that will eventually house the clones.
db12c : The remote non-CDB.
cdb3 : The remote CDB, used for cloning a remote PDB (pdb5).

On remote

On the remote machine, we have to however assure couple stuff:

Create user and verify archivelog

export ORAENV_ASK=NO
export ORACLE_SID=cdb3
. oraenv
export ORAENV_ASK=YES

sqlplus / as sysdba

CONN / AS SYSDBA

COLUMN property_name FORMAT A30
COLUMN property_value FORMAT A30

SELECT property_name, property_value
FROM   database_properties
WHERE  property_name = 'LOCAL_UNDO_ENABLED';

PROPERTY_NAME                  PROPERTY_VALUE
------------------------------ ------------------------------
LOCAL_UNDO_ENABLED             TRUE

SQL>


SELECT log_mode
FROM   v$database;

LOG_MODE
------------
ARCHIVELOG

SQL>

On local

Now, we can create a DB link on the local machine and then we can create the PDB itself :)

Create DB Link

CDB3=
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = my-server.my-domain)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = cdb3)
    )
  )
  
export ORAENV_ASK=NO
export ORACLE_SID=cdb1
. oraenv
export ORAENV_ASK=YES

sqlplus / as sysdba

CREATE DATABASE LINK clone_link
  CONNECT TO c##remote_clone_user IDENTIFIED BY remote_clone_user USING 'cdb3';

-- Test link.
DESC user_tables@clone_link

CREATE PLUGGABLE DATABASE pdb5new FROM pdb5@clone_link;

Pluggable database created.

SQL>

COLUMN name FORMAT A30

SELECT name, open_mode FROM v$pdbs WHERE name = 'PDB5NEW';

NAME                           OPEN_MODE
------------------------------ ----------
PDB5NEW                        MOUNTED

SQL>

ALTER PLUGGABLE DATABASE pdb5new OPEN;

SELECT name, open_mode FROM v$pdbs WHERE name = 'PDB5NEW';

NAME                           OPEN_MODE
------------------------------ ----------
PDB5NEW                        READ WRITE

SQL>
  • oracle_multitenant_overview.1636665946.txt.gz
  • Last modified: 2021/11/11 21:25
  • by andonovj