2. CDB根容器与种子容器

在Oracle多租户架构中,CDB(Container Database,容器数据库)并不是一个“大号普通数据库”,而是由若干容器(Container)组成的集合。其中有两个容器从CDB创建那一刻起就存在,并且用户不能删除、不能改名,它们就是根容器(ROOT,容器ID为CDB$ROOT)和种子容器(PDB$SEED,容器ID通常为2)。理解这两个容器的定位,是理解整个多租户体系“谁存放公共元数据、谁负责被克隆”的关键。

一、ROOT$:CDB的“公共字典与中枢”

ROOT容器是CDB的根,它保存的是整个CDB共享的元数据与公共对象,而不是某个业务应用的数据。具体来说,ROOT中主要包含:

  • 数据字典基表:如OBJ$、TAB$、COL$、USER$等底层字典表,它们记录所有容器中对象的定义信息。
  • 公共用户与公共角色:例如SYS、SYSTEM、DBSNMP,以及C##开头的公共用户(如C##DBA),这些用户在所有PDB中可见。
  • 公共对象与公共权限:如DBA_、ALL_、USER_系列视图的定义,以及SELECT ANY DICTIONARY等系统权限。
  • CDB级参数与配置:如DB_NAME、DB_DOMAIN、COMPATIBLE、ENABLE_PLUGGABLE_DATABASE等。

需要特别强调的是:ROOT本身不是用来存放业务数据的。虽然可以以SYS或SYSTEM身份在ROOT中建表,但这是极不推荐的做法,因为ROOT中的对象会被所有PDB“看到”,容易造成命名冲突和权限混乱。ROOT的正确角色是“公共字典的宿主”和“CDB级管理的入口”。

从连接角度看,当使用sqlplus / as sysdba登录时,默认就处于ROOT容器。可以通过以下命令确认当前容器:

SQL> SHOW CON_NAME

CON_NAME
------------------------------
CDB$ROOT

SQL> SELECT CON_ID, NAME, OPEN_MODE FROM V$CONTAINERS;

    CON_ID NAME       OPEN_MODE
---------- ---------- ----------
         1 CDB$ROOT   READ WRITE
         2 PDB$SEED   READ ONLY
         3 PDB1       READ WRITE

可以看到,ROOT的OPEN_MODE是READ WRITE,而种子容器是READ ONLY。这个差异正是本节要重点讨论的第二个容器。

二、PDB$SEED:只读的“模板容器”

种子容器PDB$SEED是CDB创建时自动生成的一个特殊PDB,它的核心特征是:

  • 始终以只读(READ ONLY)方式打开,无法以读写方式打开。
  • 不能被删除、不能改名、不能直接连接进行业务操作。
  • 包含一个“空白”PDB所需的全部系统对象:数据字典、系统表空间SYSTEM、SYSAUX、USERS、TEMP,以及PDBADMIN等公共用户。
  • 不包含任何用户业务数据,也不应被修改。

为什么种子容器必须只读?因为它的唯一用途是作为克隆模板。当执行CREATE PLUGGABLE DATABASE创建新PDB时,Oracle会以PDB$SEED为源,复制其数据文件,生成一个新的PDB。如果种子容器可写,那么任何一次误操作都可能污染模板,导致后续所有新建PDB都继承错误状态。只读特性是一种保护机制。

验证种子容器状态:

SQL> ALTER SESSION SET CONTAINER = PDB$SEED;
SQL> SHOW CON_NAME

CON_NAME
------------------------------
PDB$SEED

SQL> SELECT NAME, OPEN_MODE FROM V$PDBS WHERE NAME = 'PDB$SEED';

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

尝试在种子容器中建表会直接报错,例如:

SQL> CREATE TABLE t_seed_test (id NUMBER);
CREATE TABLE t_seed_test (id NUMBER)
*
ERROR at line 1:
ORA-16000: database or pluggable database open for read-only access

这个报错正是只读特性的直接体现,也是保护模板不被破坏的“硬约束”。

三、种子容器的克隆用途

种子容器最典型的用途是快速创建结构一致的新PDB。语法如下:

CREATE PLUGGABLE DATABASE pdb_new
  ADMIN USER pdbadmin IDENTIFIED BY "Oracle_123"
  FILE_NAME_CONVERT = ('/u01/app/oracle/oradata/CDB/pdbseed/',
                       '/u01/app/oracle/oradata/CDB/pdb_new/');

执行后,Oracle会从PDB$SEED复制数据文件到新路径,并创建一个全新的PDB。新PDB默认包含与种子容器相同的系统结构,但不含任何业务数据。之后可以打开并连接:

ALTER PLUGGABLE DATABASE pdb_new OPEN;
ALTER SESSION SET CONTAINER = pdb_new;

这种“从种子克隆”的方式,保证了每个新PDB在系统层面的一致性,也避免了手工建库的繁琐。除了创建新PDB,种子容器还常用于:

  • 作为PDB克隆的基准:在CREATE PLUGGABLE DATABASE ... FROM PDB$SEED中显式指定源。
  • 作为PDB快照/刷新测试的参照:对比新PDB与种子的系统对象差异。
  • 作为教学与排障的“干净样本”:当怀疑某个PDB系统字典异常时,可与种子容器对比。

四、种子容器的限制与注意事项

虽然种子容器非常有用,但它的限制也很明确:

  • 不能以读写方式打开,因此不能在其中创建用户、表、索引等业务对象。
  • 不能删除或重命名,DROP PLUGGABLE DATABASE PDB$SEED会直接失败。
  • 不能直接作为业务PDB使用,即使强行连接,也只能查询,不能写入。
  • 不应修改其数据文件,否则可能影响后续所有克隆操作。
  • 备份策略需覆盖:虽然种子容器只读,但它仍是CDB的一部分,RMAN备份CDB时会包含它。
注意:不要试图通过ALTER PLUGGABLE DATABASE PDB$SEED OPEN READ WRITE来“解锁”种子容器,该操作会报错ORA-65019: pluggable database PDB$SEED already open或直接拒绝。种子容器的只读属性是设计使然,不是配置遗漏。

五、ROOT与PDB$SEED的关系图解

下面用一张结构关系图,把ROOT、PDB$SEED与普通PDB在CDB中的位置、打开模式以及克隆方向表达清楚。图中同时标出“只读保护”和“克隆来源”两条关键关系。

CDB 容器结构:ROOT 与 PDB$SEED 的定位 CDB(容器数据库) CDB$ROOT(根容器) CON_ID = 1 OPEN_MODE = READ WRITE 公共数据字典 / 公共用户 / 公共权限 CDB级参数与配置 PDB$SEED(种子容器) CON_ID = 2 OPEN_MODE = READ ONLY 空白PDB模板 / 系统表空间 不可删除 / 不可改名 / 不可写 PDB1 READ WRITE 业务数据 PDB2 READ WRITE 业务数据 PDB3 READ WRITE 业务数据 公共字典支撑 克隆来源(CREATE PDB ... FROM PDB$SEED) ROOT 提供公共字典与CDB级管理入口;PDB$SEED 提供只读模板,用于克隆出结构一致的新PDB

从图中可以清晰看到:ROOT位于CDB的顶层,负责公共字典和CDB级管理;PDB$SEED与ROOT并列,但以只读方式存在,并通过克隆箭头指向各个业务PDB。普通PDB(PDB1、PDB2、PDB3)以读写方式打开,承载实际业务数据。三者分工明确,共同构成多租户数据库的基础骨架。

六、实践中的判断与检查

在日常运维中,遇到“新建PDB后系统对象异常”“PDB无法打开”“克隆失败”等问题时,第一步往往就是检查ROOT和PDB$SEED的状态。以下是一组常用检查命令:

-- 查看所有容器及其打开模式
SELECT CON_ID, NAME, OPEN_MODE, RESTRICTED FROM V$CONTAINERS ORDER BY CON_ID;

-- 确认当前容器
SELECT SYS_CONTEXT('USERENV','CON_NAME') FROM DUAL;

-- 查看种子容器数据文件
SELECT FILE_NAME FROM CDB_DATA_FILES WHERE CON_ID = 2;

-- 查看ROOT中的公共用户
SELECT USERNAME, COMMON FROM CDB_USERS WHERE CON_ID = 1 AND COMMON = 'YES';

如果发现PDB$SEED的OPEN_MODE不是READ ONLY,或者V$CONTAINERS中缺少CON_ID=2的记录,说明CDB结构可能已损坏,需要立即从备份恢复或联系Oracle支持。正常情况下,ROOT为读写、种子为只读、业务PDB为读写,这是CDB健康运行的基本标志。

记忆要点:ROOT是“公共字典+管理入口”,可读写;PDB$SEED是“只读模板”,只用于克隆,不能写、不能删、不能改名。新建PDB时,默认从PDB$SEED复制系统结构,因此种子容器的完整性直接决定新PDB的可用性。

总结来说,ROOT$与PDB$SEED虽然都不承载业务数据,但它们在CDB中扮演着不可替代的角色:前者是公共元数据的中枢,后者是标准化PDB的克隆源。理解它们的只读特性与克隆用途,是掌握Oracle多租户架构治理的第一步,也是后续进行PDB创建、克隆、迁移和排障的基础。