Oracle 12C 新特性之一:多租户架构,CDB和PDB(二)

一,CDB

CDB中的容器是用户,对象以及相关结构的集合,对于应用来说,它就等于一个逻辑上的独立数据库。

在CDB里面,每一个容器都有一个唯一的ID和名字。

root以及每个PDB都是容器。PDB分离了数据和操作,对于用户或者应用来说,每一个PDB表现的跟传统的非CDB一样。

1,ROOT

root容器存储了所有PDB都能够访问的用户/用户对象/非用户对象等数据。并且每个CDB只有一个root,CDB$ROOT,它存储了用来管理PDB的系统元数据。

所有的PDB都在ROOT之下。

root并不存储用户数据,因此,你不可以把用户数据加到root里面或者修改系统提供的用户。

但是,你可以创建公共用户和角色来进行数据库管理。

拥有指定权限的公共用户可以在不同PDB之间切换。

2,PDB

PDB使用户创建的数据的集合,它对外的表现形式就是一个独立的数据库。

每一个PDB由CDB的公共用户SYS所有,而不是PDB里创建的用户。

2.1,PDB的目的

  • 存储单独给某个特定应用使用的数据

比如说,一个sales应用可以有它自己的直属PDB,而HR应用则使用另一个PDB。

  • 把数据迁移到不同的CDB

因为PDB数据库是自包容的,也就是一个完整的个体,所以你可以把它从一个CDB上面拔下来然后插到另一个CDB上面。

  • 在PDB之间隔离授权

一个拥有指定权限的本地用户或者公共用户可以授予对一个包的执行权限给PDB里面的PUBLIC用户。

2.2,PDB的名字

CDB里面每个PDB的名字必须是唯一的,并且命名规则和service name一样。

另外,因为PDB有一个和它自己的名字相关的service,一个PDB名字在它所注册的监听里面是唯一的,也就是如果多个CDB使用同一个监听,那么在所有的这些CDB里面,PDB的名字也必须是唯一的。

用户创建的PDB的名字的首字符必须是必须是字母或者数字,然后这些的字符则可以是字母,数字或者下划线_。

因为service name是大小写不敏感的,所以PDB名字也是大小写不敏感的,并且会显示为大写,即便指定的是小写。

2.3,PDB里面名字和权限的范围

PDB有独立的命名空间,它会影响下面的结构:

  • schemas

一个PDB里面的schema可以和不同的PDB里面的schema一样,这两个schema可以代表不同的两个本地用户,在连接的时候,由PDB进行识别并且解析,也可以是指一个公共用户。

  • objects

在PDB里面object必须拥有唯一的名字,不需要跨PDB唯一。不同PDB中即便名字相同,两者也是不同的object。

DB Directory是非用户对象的一种。在一个CDB里面,公共用户SYS持有direcotries。

因为每一个PDB都有他们自己的SYS用户,所以你用哪个PDB的SYS创建了directories,该directories就属于该PDB。

在名字解析的时候,数据库仅仅会查询用户所连接的容器的数据字典。

2.4,PDB之间的DB LINK

在一个CDB里面,所有的数据库对象都属于schema,而schema则属于container。

因为PDB对于用户来说就是非CDB的,所以schema在容器里面必须是唯一的。比如说,salespdb和hrpdb都可以有一个rep用户。但这两个rep用户之间是相互独立的。

PDB里面的用户如果想要访问其他PDB的对象,则必须使用DB LINK。有点类似于非CDB,不同数据库之间的数据访问。

3,CDB中的数据字典结构

从用户和应用角度来看,CDB里面的每一个容器的数据字典信息是隔离的,因为它看起来是非CDB的。

比如说,每一个PDB中的DBA_OBJECTS视图会显示不同的行数。这种数据字典隔离的方式可以使数据库可以单独管理某一个PDB。

3.1,数据字典隔离的目的

在一个没有任何用户数据的新创建的非CDB里面,数据字典仅仅包含了系统元数据。比如说TAB$表只包含了那些oracle自带的表,比如TRIGGER$和SERVICE$表。

下图是刚开始的时候这三个表的内容:

 

 如果用户创建了自己的用户和表,那么数据字典现在就会变成混合状态。TAB$表会含有一些数据描述用户的表。

 

在CDB里面,数据字典元数据分割成了root和PDBs两部分。如下图所显示的,employees和departments表存储在PDB里面,跟这些用户表相关的数据字典信息也同样存储在PDB里面。

所以PDB中的TAB$表里有一行employees表和一行departments表的数据。而系统自带的表的信息则存储在root中。

如下图所显示的,PDB中的数据字典包含了指向root的数据字典的指针。而oracle自带的对象,比如说数据字典表的定义以及PL/SQL包这些,则只摆放在了root中。

这种结构有以下两个主要目的:

  • 减少冗余

比方说,通过仅仅把DBMS_ADVISOR包存储在CDB$ROOT中,那么就不用在每个PDB都保留一个副本,变相减少了磁盘空间的消耗。

  • 方便数据库升级

如果数据字典表的定义存储在每个PDB中,并且这些定义在新的版本里有所变动,那么每一个PDB都需要单独进行升级来应用这些变更。

而仅仅存储在root中的话就可以避免这个问题。

 3.2,CDB Root中的元数据和对象链接

使用一个内部机制来隔离数据字典信息。

具体来说,oracle使用以下的自动化管理的指针:

  • Metadata links

Oracle数据库把数据字典对象的元数据仅仅存储在root中。比如说,数据字典表OBJ$的列定义信息就只是存储在root中。

在上面的示意图中,PDB去读OBJ$表时,OBJ$这个表的定义信息(列名,列的数据类型等)是存储在root中,所以PDB使用metadata link来指向root中的OBJ$表的定义信息,但是PDB持有的OBJ$的数据(即行数据)则还是存放在PDB中。

打个比方,如果你在hrpdb中创建了一个表,表名是mytable,并且往里面插入了数据。那些这些数据是存储在PDB文件中。

PDB和ROOT中的数据字典视图包含了不同的数据。比如说,描述mytable的信息存储在hrpdb中的OBJ$表,而不是在root中的OBJ$表。所以,在root中查询DBA_OBJECTS和在hrpdb中查询,得到的结果是不一样的。

  • Object links

在某些情况下,oracle会把一个object的数据(不是元数据)仅仅存储在root中。比如说,AWR数据。每一个PDB使用一个叫做object link的内部机制来指向root中的AWR数据,从而在每个独立的PDB创建如DBA_HIST_ACTIVE_SESS_HISTORY和DBA_HIST_BASELINE的视图。

Oracle自动创建和管理object以及metadata links.用户不能自己添加,修改和删除它们。

3.3,CDB中的容器数据对象

 一个容器数据对象是一个表或者视图,其中包含了多个容器(可能还有整个CDB)的数据,并且通过这些对象限制特定公共用户只能访问某些容器的数据。

比如说oracle自带的视图,比如说名字是以V$和CDB_开头的。

所有的容器对象都有一个CON_ID列,下图是所有ID表示的意思:

在一个CDB里面,对于每一个DBA_开头的视图,都有一个相对应的CDB_视图。

这些CDB_视图的所有者是相对应的DBA_视图的所有者。下图显示了字典视图的不同类别之间的关系。

当当前的容器是一个PDB的时候,一个用户只可以查看当前PDB的数据字典信息。

对于应用来说,数据字典信息表现得如同非CDB一样。如果当前容器是root,那么,一个公共用户可以查询CDB_视图来查看root的元数据和那些它有权限的PDB。

下表显示了涉及CDB_视图查询的场景

 3.4 CDB中的数据字典存储

CDB中存储元数据的数据字典全部只存储在SYSTEM表空间中。

而存储某个PDB的元数据的数据字典则存储在PDB本身的表空间中。PDB的表空间包含了应用后端的数据和元数据。

所以,每组数据字典都存储在它自己专用的表空间中。

4,Current Container

对于每一个会话来说,当前容器是指会话正在运行的环境。它可以是root(仅仅支持公共用户)或者PDB。

因为每个容器中的数据字典都是隔离的,所以每个会话所在的容器都是确切的。oracle使用当前容器的数据字典来进行名字解析和权限认证。

5,跨容器的操作

一个跨容器的操作是一条会影响以下方面的DDL语句:

• 影响CDB本身

• 影响多个容器

• 影响多个实体,比如说出现在多个容器中的公共用户或者公共角色

• 使用DDL对另一个容器进行操作

只有公共用户可以连接到root来进行跨容器的操作,比如说,使用SYSTEM用户来授权给另一个公共用户,以及使用ALTER DATABASE ... RECOVER来恢复整个CDB。

 

二,CDB中的service

客户端必须使用service来连接到PDB。

一个前台进程,或者说一个会话,在它的存活周期的每一时刻都有一个唯一定义的当前容器。

下图显示两个客户端使用不同的监听连接到PDB:

 

 

1,在CDB里创建service

当你创建一个PDB的时候,数据库会在CDB里面自动创建和启动一个服务。

这个service在DBA_SERVICES.PDB列显示了哪个PDB是它对应的容器。

service和PDB的名字是一样的。PDB的名字必须是一个有效的service名字,并且必须是在CDB内唯一。

比如说,在上图中,名为hrpdb的PDB有一个默认的service名字hrpdb。默认的service不能够被删除。

你可以给PDB创建额外的services。每一个额外的service把它的PDB设置为初始当前容器。

在上图中,erppdb和hrpdb都有一个非默认的service。

创建,维护以及删除额外的service的方式和非CDB环境是一样的。

 

注意:

当在同一台服务器上有两个或者多个CDB使用同一个监听,并且这些CDB里面的两个以上的PDB使用同样的service名字的时候,

一个指向这个service名字的连接会随机连接到其中的某一个PDB。为了避免错误的连接,必须确保在计算机上的PDB的service名字是唯一的,或者为每一个CDB配置一个单独的监听。

2,连接CDB里面的容器

拥有恰当权限的CDB管理员账号可以连接CDB里面的任意一个容器。

管理员可以使用以下的方式来连接:

  • 使用ALTER SESION SET CONTAINER语句,这种方式对连接池和高级CDB管理都有用,可以在容器之间切换。比如说,一个CDB管理员可以在一个会话连接到root,然后在同一个会话接着切换到PDB。使用这种方式,需要有SET CONTAINER的系统权限。
  • 直接连接到PDB,这种方式要求用户有CREATE SESSION权限。

例子:公共用户SYSTEM查询当前容器的名字和CDB中的PDB的名字。

posted @ 2019-10-31 15:38  Ryan_Wo  阅读(1130)  评论(0编辑  收藏  举报