Oracle12.1发布至今已有多年,但国内Oracle12C的用户并不多,随着12.2在去年的发布,选择安装Oracle12c的客户量明显增加,在接下来的几年中,Oracle12c将逐步得到普及。
目前关于12C新特性的文章很多,但大多都不成体系,本次的文章是一个非常完整、连贯的系列,将带你全面的从基础到深入全方位的理解Oracle12C。
本篇为Oracle12c系列的开篇文章《Oracle12c系列(1)MultitenantContainer》。可插入数据库的概念OracleMultitenantContainerDatabase(CDB),即多租户容器数据库,是Oracle12C引入的特性,指的是可以容纳一个或者多个可插拔数据库的数据库,这个特性允许在CDB容器数据库中创建并且维护多个数据库,在CDB中创建的数据库被称为PDB,每个PDB在CDB中是相互独立存在的,在单独使用PDB时,与普通数据库无任何区别。CDB根容器数据库的主要作用就是容纳所有相关的PDB的元数据,以及在CDB中对所有的PDB进行管理。
多租户环境的组成ROOTRoot容器数据库,是CDB环境中的根数据库,在根数据库中含有主数据字典视图,其中包含了与Root容器有关的元数据和CDB中所包含的所有的PDB信息。在CDB环境中被标识为CDB$ROOT,每个CDB环境中只能有一个Root容器数据库。CDBseedCDBseed为PDB的种子,其中提供了数据文件,在CDB环境中被标识为PDB$SEED,是创建新的PDB的模板,你可以连接PDB$SEED,但是不能执行任何事物,因为PDB$SEED是只读的,不可进行修改。PDBsPDB数据库,在CDB环境中每个PDB都是独立存在的,与传统的Oracle数据库基本无差别,每个PDB拥有自己的数据文件和objects,唯一的区别在于PDB可以插入到CDB中,以及在CDB中拔出,并且在任何一个时间点之上PDB必须拔出或者插入到一个CDB中,当用户链接PDB时不会感觉到根容器和其他PDB的存在。CDBwithPDBs
sys.ora12c>showpdbsCON_IDCON_NAMEOPENMODERESTRICTED------------------------------------------------------------2PDB$SEEDREADONLYNO3ORA12CPDBREADWRITENO4PDB2MOUNTED5PDB1MOUNTED6PDB3READWRITENOsys.ora12c>PDB$SEED为CDBseed,ORA12CPDB/PDB1/PDB2/PDB3为PDB数据库。
ApplicationContainers在12cR2版本中,Oracle对多租户功能进行了增强,在CDBroot容器中可以创建一个叫做Applicationroot的容器,可在其内创建多个依赖于Applicationroot的ApplicationPDBs,架构图如下:
ApplicationContainersinaCDB
Application
更多的关于ApplicationContainers相关内容请参考之前的ApplicationContainers系列:
《Oracle12cR2版本ApplicationContainers特性(1)》
《Oracle12cR2版本ApplicationContainers特性(2)》
《Oracle12cR2版本ApplicationContainers特性(3)》
CDB环境中的用户CDB环境中包含两类用户,公用用户和本地用户。
丨公用用户公用用户是在root数据库中和所有的PDB数据库中都存在的用户,公用用户必须在根容器中创建,然后此用户会在所有的现存的PDB中自动创建,公用用户标识必须以c##或者C##开头,sys和system用户是Oracle在CDB环境中自动创建的公用用户。
createuserc##yyhidentifiedbyyyh;创建完成公用用户,需要为公用用户赋予所有可插拔数据库的权限,公用用户才可以访问其他PDB,如果在连接根容器时仅仅为公用用户赋予了相关权限,那么该权限不会被传递到所有的可插拔数据库中,必须为公用用户赋予能够传递到PDB中的权限,可以创建公用角色然后赋予公用用户,或者在为公共用户付权时指定子句container=ALL;
例如:
或者grantdbatoc##yyhcontainer=all;createrolec##dbaprivscontainer=all;grantdbatoc##dbaprivscontainer=all;grantc##dbaprivstoc##yyhcontainer=all;或者grantdbatoc##yyhcontainer=all;丨本地用户本地用户指的是在PDB中创建的普通用户,只有在创建它的PDB中才会存在该用户,并且PDB中只能创建本地用户。
CDB中你需要再次了解的基础知识
丨SYSTEM/SYSAUX在CDB的数据库环境中,SYSTEM/SYSAUX表空间并不是公用,CDB$ROOT以及每个PDB都拥有自己的SYSTEM和SYSAUX表空间。
丨REDO文件在CDB环境中所有的PDB共用CDB$ROOT中的REDO文件,REDO中的条目标识REDO来自那个PDB。
在PDB中无法执行ALTERSYSTEMSWITCHLOGFILE命令,只有公用用户在ROOT容器中才可以执行该命令。
另外ALTERSYSTEMCHECKPOINT命令是可以在PDB中执行的。
丨归档在CDB环境中所有的PDB共用CDB的归档模式,以及归档文件,不可以单独为PDB设置自己的归档模式,只有特权用户连接根容器之后才可以启动归档模式。
丨UNDOMODE在12.2之前的版本中,所有的PDB共用CDB$ROOT中的UNDO文件,在12.2之后的版本中UNDO的使用模式有两种:SHAREDUNDOMODE和LOCALUNDOMODE,顾名思义,LOCALUNDOMODE就是每个PDB使用自己的UNDO表空间,但当PDB中没有自己的UNDO表空间时,会使用CDB$ROOT中的公共UNDO表空间。
查看UNDO表空间的使用模式(CDB$ROOT):
COLPROPERTY_NAMEFORA50COLPROPERTY_VALUEFORA50COLDESCRIPTIONFORA50SELECTproperty_name,property_valueFROMdatabase_propertiesWHEREproperty_name='LOCAL_UNDO_ENABLED';PROPERTY_NAMEPROPERTY_VALUE----------------------------------------LOCAL_UNDO_ENABLEDTRUE在创建CDB时使用了SHAREDUNDOMODE方式,如果后续想更改为LOCALUNDOMODE,我们可以使用如下命令更改UNDOMODE为LOCALUNDOMODE:
startupupgradealterdatabaselocalundoon;shutdownimmediatestartup更改为localundo后CDB中的所有的PDB会自动创建自己的UNDO表空间。
丨临时文件每个PDB都有自己的临时表空间,如果PDB没有自己的临时表空间文件,那么,PDB可以使用CDB$ROOT中的临时表空间。
08:42:46sys.woqu>selectcon_id,tablespace_namefromcdb_temp_files;CON_IDTABLESPACE_NAME------------------------------1TEMP3TEMPElapsed:00:00:00.1108:43:02sys.woqu>丨参数文件参数文件中只记录了根容器的参数信息,没有记录PDB级别的参数信息,在根容器中修改初始化参数,会被继承到所有的PDB中,在PDB中修改参数后,PDB的参数会覆盖CDB级别的参数,PDB级别的参数记录在根容器的pdb_spfile$视图中,但并不是所有的参数都可以在PDB中修改,可以通过v$system_parameter视图查看PDB中可修改的参数:
SELECTnameFROMv$system_parameterWHEREispdb_modifiable='TRUE'ORDERBYname;pdb_spfile$:08:37:58sys.yyh>showparameteropen_cursorsNAMETYPEVALUE----------------------------------------------------open_cursorsinteger99908:38:04sys.yyh>showparameterlocal_listenerNAMETYPEVALUE---------------------------------------------------------------local_listenerstringPDB_YYH08:38:08sys.yyh>selectpdb_uid,name,value$frompdb_spfile$;PDB_UIDNAMEVALUE$----------------------------------------------1167267009open_cursors9991167267009local_listener'PDB_YYH'Elapsed:00:00:00.0008:38:11sys.yyh>这里在PDB:1167267009中更改了open_cursors/local_listener两个参数。
丨控制文件CDB环境中只有一组控制文件,所有的PDB共用这组公共的控制文件,从任何PDB中添加数据文件都会记录到公共控制文件当中,公用用户连接根容器时,可对控制文件进行管理。
20:51:03sys.woqu>showparametercontrol_filesNAMETYPEVALUE-----------------------------------------------------------------------------control_filesstring/u01/app/oracle/oradata/woqu/control01.ctl,/u01/app/oracle/oradata/woqu/control02.ctl20:51:06sys.woqu>20:50:55sys.woqupdb>showparametercontrol_filesNAMETYPEVALUE-----------------------------------------------------------------------------control_filesstring/u01/app/oracle/oradata/woqu/control01.ctl,/u01/app/oracle/oradata/woqu/control02.ctl20:51:23sys.woqupdb>丨告警日志以及跟踪文件在CDB中所有的PDB共用一个告警日志和一组跟踪文件,所有的PDB告警信息都会写入同一个告警日志中。
丨时区在CDB环境中可以为CDB以及所有的PDB设置相同的时区,也可以为每个PDB设置单独的时区。
20:51:50sys.woqu>showpdbsCON_IDCON_NAMEOPENMODERESTRICTED------------------------------------------------------------2PDB$SEEDREADONLYNO3WOQUPDBREADWRITENO20:52:00sys.woqu>selectdbtimezonefromdual;DBTIME------+00:00Elapsed:00:00:00.0020:52:01sys.woqu>20:51:53sys.woqupdb>selectdbtimezonefromdual;DBTIME------+08:00Elapsed:00:00:00.0020:52:02sys.woqupdb>丨字符集在CDB中定义字符集也可以应用于它所含有的PDB中,每个PDB也可以有自己的字符集设置。
20:52:33sys.woqu>SELECTa.value||'_'||b.value||'.'||c.valueNLS_LANG20:52:332FROMnls_database_parametersa,nls_database_parametersb,nls_database_parametersc20:52:333WHEREa.parameter='NLS_LANGUAGE'ANDb.parameter='NLS_TERRITORY'ANDc.parameter='NLS_CHARACTERSET';NLS_LANG----------------------------------------AMERICAN_AMERICA.AL32UTF8Elapsed:00:00:00.0620:52:33sys.woqu>20:52:33sys.woqu>20:52:36sys.woqupdb>SELECTa.value||'_'||b.value||'.'||c.valueNLS_LANG20:52:362FROMnls_database_parametersa,nls_database_parametersb,nls_database_parametersc20:52:363WHEREa.parameter='NLS_LANGUAGE'ANDb.parameter='NLS_TERRITORY'ANDc.parameter='NLS_CHARACTERSET';NLS_LANG----------------------------------------AMERICAN_AMERICA.ZHS16GBKElapsed:00:00:00.0820:52:36sys.woqupdb>20:52:36sys.woqupdb>丨数据字典视图与动态性能视图在CDB环境中引入了CDB级别的数据字典视图,它的级别高于DBA_/ALL_/USER_,CDB级别的数据字典视图含有所有PDB的元数据信息,其中增加了con_id列,con_id为CDB中所有容器唯一标识符,其中con_id为0的是CDB$ROOT,con_id为2的是PDB$SEED,每个PDB在CDB中都会分配一个唯一的con_id。如果要想查看CDB级别的数据字典视图,必须使用公用用户在跟容器中查看,并且要查看的PDB必须处于open状态,才可以看到PDB中的信息。
20:53:42sys.woqu>showpdbsCON_IDCON_NAMEOPENMODERESTRICTED------------------------------------------------------------2PDB$SEEDREADONLYNO3WOQUPDBREADWRITENO20:53:45sys.woqu>20:54:40sys.woqu>selectcon_id,pdb_id,pdb_name,dbid,statusfromcdb_pdbs;CON_IDPDB_IDPDB_NAMEDBIDSTATUS---------------------------------------------------------------22PDB$SEED2834527297NORMAL33WOQUPDB3238406520NORMAL20:54:43sys.woqu>CDB的创建如果要使用可插拔数据库的功能,需要在创建数据库时专门指定启用可插拔数据库,创建CDB通常有如下两种方式:
使用DBCA图形工具创建CDB这里需要注意的是Oracle12.2之后支持LOCALUNDO,这里注意需要手动要勾选LOCALUNDO选项。CREATEDATABASE语句创建CDB在使用脚本创建CDB时Oracle提供了两种方法,一种是使用OMF,另外一种是非OMF的方式,注意参数文件中需要将ENABLE_PLUGGABLE_DATABASE设置为TRUE。这里演示使用非OMF方式创建CDB,数据名称为ora12c:
1.设置ENABLE_PLUGGABLE_DATABASE参数为TRUE,参数文件如下:
audit_file_dest='/u01/app/oracle/admin/ora12c/adump'audit_trail='none'compatible='12.2.0'control_files='/u01/app/oracle/oradata/ora12c/control01.ctl','/u01/app/oracle/oradata/ora12c/control02.ctl'db_block_size=8192db_domain='linux.com'db_name='ora12c'diagnostic_dest='/u01/app/oracle'enable_pluggable_database=truememory_target=801mnls_language='AMERICAN'nls_territory='AMERICA'remote_login_passwordfile='EXCLUSIVE'undo_tablespace='UNDOTBS1'2.创建相应目录以及设置环境变量
exportORACLE_SID=ora12cexportORACLE_HOME=$ORACLE_BASE/product/12.2.0/dbhome_1exportPATH=$ORACLE_HOME/bin:$ORACLE_HOME/OPatch:$ORACLE_HOME/perl/bin:$ORACLE_HOME/jdk/bin:$PATH3.CREATEDATABASE脚本createdb.sql如下:
CREATEDATABASEora12cUSERSYSIDENTIFIEDBYoracleUSERSYSTEMIDENTIFIEDBYoracleLOGFILEGROUP1('/u01/app/oracle/oradata/ora12c/redo01a.log','/u01/app/oracle/oradata/ora12c/redo01b.log')SIZE100MBLOCKSIZE512,GROUP2('/u01/app/oracle/oradata/ora12c/redo02a.log','/u01/app/oracle/oradata/ora12c/redo02b.log')SIZE100MBLOCKSIZE512,GROUP3('/u01/app/oracle/oradata/ora12c/redo03a.log','/u01/app/oracle/oradata/ora12c/redo03b.log')SIZE100MBLOCKSIZE512MAXLOGHISTORY1MAXLOGFILES16MAXLOGMEMBERS3MAXDATAFILES1024CHARACTERSETAL32UTF8NATIONALCHARACTERSETAL16UTF16EXTENTMANAGEMENTLOCALDATAFILE'/u01/app/oracle/oradata/ora12c/system01.dbf'SIZE700MREUSEAUTOEXTENDONNEXT10240KMAXSIZEUNLIMITEDSYSAUXDATAFILE'/u01/app/oracle/oradata/ora12c/sysaux01.dbf'SIZE550MREUSEAUTOEXTENDONNEXT10240KMAXSIZEUNLIMITEDDEFAULTTABLESPACEdeftbsDATAFILE'/u01/app/oracle/oradata/ora12c/deftbs01.dbf'SIZE500MREUSEAUTOEXTENDONMAXSIZEUNLIMITEDDEFAULTTEMPORARYTABLESPACEtempts1TEMPFILE'/u01/app/oracle/oradata/ora12c/temp01.dbf'SIZE20MREUSEAUTOEXTENDONNEXT640KMAXSIZEUNLIMITEDUNDOTABLESPACEundotbs1DATAFILE'/u01/app/oracle/oradata/ora12c/undotbs01.dbf'SIZE200MREUSEAUTOEXTENDONNEXT5120KMAXSIZEUNLIMITEDENABLEPLUGGABLEDATABASESEEDFILE_NAME_CONVERT=('/u01/app/oracle/oradata/ora12c/','/u01/app/oracle/oradata/ora12c/pdbseed/')SYSTEMDATAFILESSIZE125MAUTOEXTENDONNEXT10MMAXSIZEUNLIMITEDSYSAUXDATAFILESSIZE100MUSER_DATATABLESPACEusertbsDATAFILE'/u01/app/oracle/oradata/ora12c/pdbseed/usertbs01.dbf'SIZE200MREUSEAUTOEXTENDONMAXSIZEUNLIMITED;这段代码中”ENABLEPLUGGABLEDATABASE”之后部分与PDB有关,其他部分与创建传统的Oracle数据库语句均相同。
FILE_NAME_CONVERT
子句指定了使用’
/u01/app/oracle/oradata/ora12c/’中的文件名在’/u01/app/oracle/oradata/ora12c/pdbseed/’中生产CDBseeds。
USER_DATA_TABLESPACE
子句可以在容器中创建额外的表空间,这个表空间在后续使用PDB$SEED创建PDB时会被复制到PDB中。
4.将数据库启动到nomount状态,然后执行上面createdb.sql脚本创建CDB
startupnomount;@createdb.sql当数据库创建成功之后可以看到新建立的数据库被加入到/etc/oratab文件中。
#cat/etc/oratab+ASM:/u01/app/11.2.0/grid:Nora12c:/u01/app/oracle/product/12.2.0/dbhome_1:Norcl:/u01/app/oracle/product/11.2.0/dbhome_1:N#lineaddedbyAgentnewdb:/u01/app/oracle/product/12.2.0/dbhome_1:Nyyh:/u01/app/oracle/product/12.2.0/dbhome_1:N5.查看监听,根容器的服务ora12c.linux.com已经被注册到监听中。
Service"ora12c.linux.com"has1instance(s).Instance"ora12c",statusREADY,has1handler(s)forthisservice...6.运行catcdb.sql脚本创建CDB相关视图:
@?/rdbms/admin/catcdb.sql注意事项:1.在catcdb.pl执行过中需要输入两个参数,文档中并没有指出是什么参数.
第一个参数应输入:
$ORACLE_HOME/rdbms/admin第二个参数应输入:
catcdb.pl2.环境变量中必须将$ORACLE_HOME/perl/bin指定到PATH中,否则报如下错误:
Can'tlocateTerm/ReadKey.pm3.需要将$
ORACLE_HOME/perl/lib/5.22.0/x86_64-linux-thread-multi/Hash中的catcdb.pl文件内容:
4.切换到$
ORACLE_HOME/perl/lib/5.22.0/x86_64-linux-thread-multi/Hash目录中,然后sqlplus连接到数据,在执行catcdb.sql,否则报如下错误:
7.开启localundomode(因为上面再创建CDB时没有加入localundomode子句)
sys.ora12c>shutdownimmediatesys.ora12c>startupupgradesys.ora12c>alterdatabaselocalundoon;Databasealtered.Elapsed:00:00:00.72查看是否为localundomode:
SELECTproperty_name,property_valueFROMdatabase_propertiesWHEREproperty_name='LOCAL_UNDO_ENABLED';PROPERTY_NAMEPROPERTY_VALUE----------------------------------------LOCAL_UNDO_ENABLEDTRUEElapsed:00:00:00.02sys.ora12c>重启数据库:
shutdownimmediatestartup启动数据库的过程中会在PDB$SEED中自动创建UNDO表空间,提供给后来采用PDB$SEED方式创建PDB所使用。
PS:如果CDB中已经存在多个PDB,当在根容器中使用alterdatabaselocalundoon;开启localundomode时会自动为每个PDB创建localundo。
8.检查CDB是否已经创建成功
sys.ora12c>SELECTdbid,name,open_mode,cdb,con_idFROMv$database;DBIDNAMEOPEN_MODECDBCON_ID----------------------------------------------------323027068ORA12CREADWRITEYES0Elapsed:00:00:00.11sys.ora12c>此时CDB中含有两个容器:根容器CDB$ROOT和种子容器PDB$SEED,如下:
sys.ora12c>SELECTcon_id,dbid,con_uid,guid,nameFROMv$containers;CON_IDDBIDCON_UIDGUIDNAME---------------------------------------------------------------------1323027068150A57CDEFD150C96E0530838A8C0206ECDB$ROOT21453953285145395328550A57CDEFD160C96E0530838A8C0206EPDB$SEEDElapsed:00:00:00.00sys.ora12c>SELECTcon_id,tablespace_name,file_id,file_nameFROMcdb_data_files;CON_IDTABLESPACE_NAMEFILE_IDFILE_NAME------------------------------------------------------------------------1SYSTEM1/u01/app/oracle/oradata/ora12c/system01.dbf1SYSAUX3/u01/app/oracle/oradata/ora12c/sysaux01.dbf1UNDOTBS15/u01/app/oracle/oradata/ora12c/undotbs01.dbf1DEFTBS6/u01/app/oracle/oradata/ora12c/deftbs01.dbfElapsed:00:00:00.01sys.ora12c>showcon_idcon_nameuserCON_ID------------------------------1CON_NAME------------------------------CDB$ROOTUSERis"SYS"sys.ora12c>CDB的管理管理CDB时,通常需要使用sys用户连接根容器数据库,在操作方式上与非CDB数据库同样。
当前连接容器的信息:
1.23:03:31sys.woqu>showcon_idcon_nameuserCON_ID------------------------------1CON_NAME------------------------------CDB$ROOTUSERis"SYS"23:03:33sys.woqu>2.COLCON_IDFORA10COLCUR_CONTAINERFORA25COLCUR_USERFORA25SELECTsys_context('USERENV','CON_ID')con_id,sys_context('USERENV','CON_NAME')cur_container,sys_context('USERENV','session_user')cur_userFROMdual;CON_IDCUR_CONTAINERCUR_USER------------------------------------------------------------1CDB$ROOTSYS丨启动和停止CDB只有公用用户才可以连接根容器,并且启动和停止CDB,停止和启动与普通数据库的处理过程相同,当公用用户连接PDB时,无法启动和停止CDB:
sys.ora12c>startup默认情况下启动CDB时不会自动启动PDBs,我们可以使用手工的方式启动PDB:
ALTERPLUGGABLEDATABASE[pdb_name]OPEN;ALTERPLUGGABLEDATABASEALLOPEN;--打开所有PDBsys.ora12c>shutdownimmediate在关闭CDB时,CDB中正在运行PDSs会也会关闭,连接CDB与PDBs的session均会断开。
查看CDB环境中表空间使用情况:
withgenerator0as(selectcf.con_id,cf.tablespace_name,sum(cf.bytes)/1024/1024frmfromcdb_free_spacecfgroupbycf.con_id,cf.tablespace_name),generator1as(selectcd.con_id,cd.tablespace_name,sum(cd.bytes)/1024/1024usmfromcdb_data_filescdgroupbycd.con_id,cd.tablespace_name),generator2as(selectg0.con_id,c.namecon_name,g0.tablespace_name,g0.frm,g1.usmfromgenerator0g0,generator1g1,v$containerscwhereg0.con_id=g1.con_idandg0.tablespace_name=g1.tablespace_nameandc.con_id=g1.con_idunionselectc.con_id,c.name,ct.tablespace_name,null,sum(ct.bytes)/1024/1024fromv$containersc,cdb_temp_filesctwherec.con_id=ct.con_idgroupbyc.con_id,c.name,ct.tablespace_name)selectcon_id,casewhencon_name=LAG(con_name,1)OVER(PARTITIONBYcon_nameORDERBYtablespace_name)THENnullELSEcon_nameENDcon_name,tablespace_name,frmfreemb,usmusembfromgenerator2orderbycon_id;CON_IDCON_NAMETABLESPACE_NAMEFREEMBUSEMB-----------------------------------------------------1CDB$ROOTSYSAUX284701SYSTEM6.56258101TEMP331UNDOTBS11.9375601USERS453ORA12CPDBSYSAUX18.1253603SYSTEM1.252503TEMP643UNDOTBS1331003USERS45丨切换容器使用公用用户连接CDB后可以使用altersession的方式切换不同的容器:
altersessionsetcontainer=pdb1;altersessionsetcontainer=cdb$root;在切换容器时无需运行监听器和密码文件。只要公用用户拥有相关权限就可以切换到另外的容器中。