Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2796707
  • 博文数量: 389
  • 博客积分: 4177
  • 博客等级: 上校
  • 技术积分: 4773
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-16 23:29
文章分类

全部博文(389)

分类: Oracle

2016-05-28 17:56:18

                              ORACLE 12C Mulititenant的Object Link

   在12C中引入了多租户架构,数据字典对像分为了四个层次,USER_,ALL_,DBA_,CDB_. 基中CDB_级别是
查询整个CDB级别的所有容器中的对像.由于CDB级别的对像并不是真正的存放在cdb$root这个容器中,而
是通过查询所有的pdb中数据汇总而来,所以这样的也使得pdb可以plug和unplug到另一个容器中,在12c中
这种方式称为object link.

现在假设数据库中存在两个pdb容器
DONGDONGTANG> select con_id,name,open_mode from v$pdbs;
    CON_ID NAME  OPEN_MODE
---------- ------------------------------ ----------
2 PDB$SEED  READ ONLY
3 PDB1  READ WRITE
4 PDB2  READ WRITE

当前容器名为cdb$root

DONGDONGTANG> show con_name;
CON_NAME
------------------------------
CDB$ROOT

查询CDB级别所有的对像

DONGDONGTANG> select count(*) from cdb_objects;

通过对cdb_objects对像的定义,可以看到oracle使用了一个函数CONTAINERS()来查询所有的PDB中对像,以sys.dba_objects的栏位为准,同时该函
数会在结果集中加入了con_id列

SELECT "OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAMP",
"STATUS","TEMPORARY","GENERATED","SECONDARY","NAMESPACE","EDITION_NAME","SHARING","EDITIONABLE","ORACLE_MAINTAINED","CON_ID" 
FROM CONTAINERS("SYS"."DBA_OBJECTS");

手动在cdb$root级别创建一个表

DONGDONGTANG> create table t1 (a int);
Table created.

试图使用系统自带的container的方式访问
DONGDONGTANG> select *  FROM CONTAINERS("SYS"."T1"); 
select *
*
ERROR at line 1:
ORA-12801: error signaled in parallel query server P007
ORA-00942: table or view does not exist

由于这个表在pdb中不存在,所以报错.同时我们也可以根据提示信息看出在pdb中查询使用的是并行查询的方式.所以有大量的pdb的时候需要小心查询
CDB_级别的对像.

接下来我们在两个pdb中分别创建了表T1,然后再次查询
DONGDONGTANG> alter session set container=pdb1;

Session altered.

DONGDONGTANG> create table t1 (a int);
Table created.

DONGDONGTANG> alter session set container=pdb2;

Session altered.

DONGDONGTANG> create table t1 (a int);

Table created.

DONGDONGTANG> alter session set container=cdb$root;

Session altered.

再次在cdb$root中使用CONTAINERS,由于现在每个容器中都有表T1,现在可以返回结果了
DONGDONGTANG> select *  FROM CONTAINERS("SYS"."T1"); 

no rows selected

如果在某个pdb中表的定义不一样呢

DONGDONGTANG> alter session set container=pdb1;

Session altered.

DONGDONGTANG> drop table t1;

Table dropped.

DONGDONGTANG> create table t1 (b int,d int);

Table created

DONGDONGTANG> select * FROM CONTAINERS("SYS"."T1"); 
select *
*
ERROR at line 1:
ORA-12801: error signaled in parallel query server P006
ORA-00904: "A": invalid identifier

oracle在这个pdb中执行的时候,使用的是类似于select a from t1,由于该栏位不存在,所以报错了.

如果cdb中定义的栏位在pdb中相关的表中都有的,那么查询就不会报错

DONGDONGTANG> create table t1 (a int,d int);

Table created.

查询可以正确的返回.

DONGDONGTANG> select *  FROM CONTAINERS("SYS"."T1");  
no rows selected

现在我们在cdb$root中的t1 insert数据
DONGDONGTANG> alter session set container=cdb$root;

Session altered.

DONGDONGTANG> insert into t1 values(10);

1 row created.

DONGDONGTANG> commit;

Commit complete.

DONGDONGTANG>  select * FROM CONTAINERS("SYS"."T1"); 


A     CON_ID
---------- ----------
10    1

可以看到CONTAINERS函数对查询该记录,并且在结果中增加了一个CON_ID,表示该结果来自哪个CON_ID了.

通过container函数,我们可以看到object link的工作方式,是通过解析相关的对像栏位,再使用并行的方式
在每个pdb中执行,然后再汇总结果返回给用户,这样就实现在CDB级别查看所有数据的功能.通过对该函数我们
可以在用户级别实现同时在多个pdb中查询汇总数据的功能.


阅读(3427) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~