news 2026/10/20 15:16:11

Oracle 12c容器表空间管理:CDB/PDB避坑与ORA-00959

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Oracle 12c容器表空间管理:CDB/PDB避坑与ORA-00959

一次从11g平滑升级到12c的数据库迁移做完了,业务上新当天,应用连上数据库就报ORA-00959: tablespace does not exist。查了几轮才发现,应用连的是容器数据库下的某个PDB,而DBA同事习惯性地用老方法、连到了旧文档里写的实例上,把业务表空间建到了整个CDB的根容器里,PDB里根本看不见。这类问题在第一次接触Oracle 12c CDB架构时太容易踩了,因为表空间管理的“单位”发生了变化:不再是同一个实例下的所有用户共享一套表空间,而是每个容器各管各的表空间。这篇文章就把我在CDB环境里折腾表空间的管理经验完整梳理一遍,从连接、建表空间、扩容告警到UNDO与临时表空间的坑,给后面接手的同学省点时间。

1. 从11g跨到12c第一课:表空间不再属于实例,而是属于容器

1.1 一次典型的“沿用老经验”事故

先说那个比较常见的翻车现场。某个项目使用的数据库从11g升级到12c,当时数据库按多租户架构建成了CDB,里面有一个业务PDB。负责迁移的同事沿用了11g时代的管理习惯,用sqlplus / as sysdba登录后,直接执行了很长一串创建表空间脚本,表空间和数据文件都建在了CDB的根容器(CDB$ROOT)里。

结果是什么?业务库的表空间看起来建好了,DBA_TABLESPACES查出来是存在的,但应用连接的PDB里始终报表空间不存在。当时排查了很久:用户权限没问题,服务名没问题,表空间明明存在,为什么应用说没有?

问题就出在“容器”上。CDB$ROOT里创建的表空间对PDB完全不可见。这在Non-CDB时代是不可能出现的情况,因为那时候一个实例对应一个数据库,不存在“表空间归属”的歧义。到了12c,如果不先确认自己当前在哪个容器里就执行DDL,很容易把对象建错地方,而且错得非常隐蔽。

1.2 CDB、PDB与表空间的归属关系

Oracle 12c引入多租户架构之后,一个实例可以承载一个CDB(容器数据库),CDB里又包含:

  • CDB$ROOT:根容器,存放Oracle系统元数据和公共对象;
  • PDB$SEED:种子容器,专门用来创建新PDB的模板,平时不能被修改;
  • 一个或多个PDB:用户真正的业务容器,业务数据、用户、业务表空间都放在这里。

用生活化的类比:CDB就像一个小区,CDB$ROOT是小区物业办公室,PDB$SEED是毛坯样板间,而PDB是业主自己装修的套间。每个套间都有自己的水电表(SYSTEM表空间)、配电箱(TEMP表空间)、管道(UNDO表空间),物业办公室里的设备跟业主套间里的设备互不通用。

所以,在12c里管理表空间,第一反应不该是“我要在实例上创建表空间”,而应该是“我当前在哪个容器,我要给哪个容器创建表空间”。这也是整个CDB表空间管理和老版本最大的思维差异。

有一点要特别提醒:虽然12c在创建数据库时可以选择Non-CDB模式,但从12.2开始默认就是CDB,很多安装向导也默认走了多租户。如果你不主动确认容器关系,极大概率会踩到我上面说的坑。后面所有命令和排查逻辑,都必须围绕容器上下文来展开。

2. 连接哪个库先搞清楚:SERVICE_NAME、CONTAINER_ID与三条关键视图

2.1 一个连接错位导致的“表空间消失”

再说第二个高频问题:觉得“表空间怎么莫名其妙不见了”。其实不是不见了,是连接错了容器。

在CDB架构下,CONN / AS SYSDBA默认登录的是CDB$ROOT。如果你在这个会话里执行:

SELECT tablespace_name FROM dba_tablespaces;

看到的是根容器下的表空间,这里面基本只有SYSTEM、SYSAUX、UNDOTBS1、TEMP等系统表空间,看不到任何PDB里的业务表空间。

而应用之所以能找到自己的业务表空间,是因为它通过类似pdb1.example.com这样的服务名连接到了具体的PDB。这时候再用PDB里的会话执行同样的SQL,才能看到属于这个PDB的表空间。

我遇到过不止一次:有人在根容器里用DBA_DATA_FILES视图查数据文件,发现某个业务表空间没有数据文件,于是断定“数据文件丢了”。实际情况是该表空间属于某个PDB,在CDB$ROOT里本来就不该查得到。

2.2 DBA_TABLESPACES、CDB_TABLESPACES怎么配合

正确做法是区分两类视图:

  • DBA_TABLESPACES、DBA_DATA_FILES:只查当前容器内的表空间和数据文件。连接的是PDB就查PDB的,连接的是根容器就查根容器的。
  • CDB_TABLESPACES、CDB_DATA_FILES:在根容器下查看整个CDB内所有容器的表空间和数据文件,每一行还带一个CON_ID字段,用于标识属于哪个容器。

举个例子,在根容器里执行:

SELECT con_id, tablespace_name, contents, bigfile FROM cdb_tablespaces ORDER BY con_id, tablespace_name;

CON_ID的含义一般是:1代表CDB$ROOT,2代表PDB$SEED,其余数字对应各个PDB。这样一条SQL就能把整个CDB下的表空间清单拉出来,比挨个PDB登录去查高效得多,也能避免“建错容器”这种问题。

如果再结合CDB_DATA_FILES看数据文件:

SELECT con_id, tablespace_name, file_name, bytes/1024/1024/1024 AS size_gb FROM cdb_data_files ORDER BY con_id, tablespace_name;

就能非常清晰地看到每个表空间的数据文件在哪个路径、属于哪个容器。遇到“表空间不存在”“文件找不到”类的报错,先跑这条SQL定位归属,能解决一大半的困惑。

2.3 切换容器的正确姿势:ALTER SESSION SET CONTAINER和SERVICE_NAME的关系

管理表空间时,很多人习惯用sqlplus / as sysdba这把“万能钥匙”,但在CDB里这把钥匙只能打开物业办公室的门。要进入具体的PDB,有两条路:

  • 通过连接字符串直接连到PDB的服务名,例如:

    CONN sys@pdb1_service AS SYSDBA

    然后这个会话里操作的就是PDB。

  • 先连到根容器,再切换容器:

    CONN / AS SYSDBA ALTER SESSION SET CONTAINER = pdb1;

    这种方式适合已经在根容器里并且拥有常用权限(比如被赋予了PDB_DBA角色)的场景。

切换之后,建议立刻做一次确认:

SHOW CON_NAME; SELECT SYS_CONTEXT('USERENV', 'CON_NAME') AS current_container FROM dual;

这两条命令输出的就是当前会话所在容器名称,一旦养成“先看容器再动手”的习惯,表空间管理就基本不会出现“改错地方”的低级错误。这也是我在团队里反复强调的规范:任何关于表空间的DDL执行前,第一件事必须是确认CON_NAME,而不是直接敲CREATE TABLESPACE。

3. 建表空间实操:从CREATE TABLESPACE到OMF文件命名

3.1 创建之前的三个确认

真正开始建表空间之前,有三个问题一定要心里有数:

  1. 当前会话在哪个容器?这决定表空间建到哪儿;
  2. 这个容器里是否已有同名表空间?CDB内不同PDB之间允许同名表空间,但同一个PDB内不能重名;
  3. 数据文件路径怎么写?是用Oracle管理的OMF方式自动生成文件名,还是手工指定绝对路径。

这三点看似基础,却直接决定了后续维护的复杂度。很多人在“建表空间”时栽跟头,不是因为不会写CREATE TABLESPACE语法,而是因为没有回答好这三个问题。

第一个问题前面已经讲了,第二个问题比较直接,第三个问题值得多说两句:在12c的CDB环境里,PDB的数据文件路径习惯上会放到按PDB名字区分的目录下,比如/u01/app/oracle/oradata/ORCL/PDB1/,这样既方便识别归属,也方便做备份和恢复。如果你启用了OMF(Oracle Managed Files),只需要设置好DB_CREATE_FILE_DEST,连文件名都不用操心,Oracle会自动生成类似/u01/app/oracle/oradata/ORCL/PDB1/datafile/o1_mf_ts_app_xxxx.dbf的名字。

3.2 完整命令与参数批注

在PDB已经切换到目标容器之后,一个典型的业务表空间创建语句长这样:

CREATE TABLESPACE ts_app DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/ts_app01.dbf' SIZE 10G AUTOEXTEND ON NEXT 1G MAXSIZE 32G EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT AUTO;

逐段拆解一下:

  • SIZE 10G:初始数据文件大小,尽量一次性规划得合理。过小会导致后面频繁扩容,过大又占用磁盘空间。
  • AUTOEXTEND ON NEXT 1G MAXSIZE 32G:开启自动扩展,每次自动增加1G,上限32G。这里要注意,MAXSIZE是针对单个数据文件的最大上限,不是表空间的硬性总大小;如果表空间需要更大容量,可以继续添加多个数据文件。
  • EXTENT MANAGEMENT LOCAL AUTOALLOCATE:本地管理表空间、区大小由Oracle自动分配。这是从9i开始就一直推荐的方式,省去手动管理PCTINCREASE、FREELISTS这些老参数。
  • SEGMENT SPACE MANAGEMENT AUTO:段空间自动管理,可以避免大量自由列表争用问题,也是默认推荐。

如果是bigfile表空间,写法略有不同:

CREATE BIGFILE TABLESPACE ts_big DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/ts_big01.dbf' SIZE 32G AUTOEXTEND ON NEXT 1G MAXSIZE 64G EXTENT MANAGEMENT LOCAL AUTO SEGMENT SPACE MANAGEMENT AUTO;

BIGFILE表空间只有一个数据文件,但这个数据文件理论上可以非常大(在8K块大小的库中可高达32T级别),适合大批量顺序写入的业务,也减少了文件数量维护成本。缺点是扩容粒度比较粗,一旦磁盘不够灵活加第二个文件。

3.3 OMF与绝对路径:怎么选

我个人的建议是:能用OMF就用OMF,尤其在容器多、PDB多的环境里,OMF能帮你省掉很多命名上的麻烦。

启用OMF后,创建表空间可以极简:

CREATE TABLESPACE ts_app;

Oracle会根据DB_CREATE_FILE_DEST参数自动决定数据文件位置和文件名。这样做的好处是:不用关心每个文件的全路径;PDB被plug/unplug时,文件路径信息更容易被自动处理。坏处是:如果你对文件系统布局有强制规范(比如审计要求、存储分层),全自动管理会让审查比较麻烦。

如果必须手工指定路径,我建议在文件路径里带上容器名和表空间名的前缀,例如:

CREATE TABLESPACE ts_app_pdb1 DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/ts_app_pdb1_01.dbf' SIZE 10G;

这样在操作系统层看到文件,也能快速对应上属于哪个PDB、哪个表空间,备查和迁移都会省心很多。

3.4 常见报错与排查

创建表空间常见的报错集中在以下两类:

第一类:ORA-65040: operation not allowed from inside a PDB。这个报错说明你正处在PDB里,却尝试执行了只能在根容器执行的操作,方向反了。反过来,在根容器下直接创建业务表空间不会报错,但结果往往不是你要的。

第二类:ORA-01537: cannot add file ... - file already part of database。多半是文件路径写重复了,或者之前建表空间失败但文件已经存在于磁盘上。处理办法:确认文件确实没有被任何表空间引用,删除残留文件后再执行。

第三类:路径不存在或者权限不够。比如ORA-01276: cannot add files,通常是因为目录不存在或者Oracle进程没有目录写权限。12c的OMF模式下,目录如果没有提前创建,Oracle不一定会自动创建,所以最好先把目录准备好并赋予正确的属主和权限。

排查这类问题,我通常先看alert日志和DBA_DATA_FILES中实际记录到的文件路径,再结合操作系统层面ls -ld确认权限,基本能快速定位。

4. 容量管理的实战链路:监控SQL、告警分析、扩容和回收

4.1 一条跑遍CDB的表空间使用率查询

表空间使用率告警,是DBA最日常的运维工作。但CDB环境下常用的老脚本有个问题:只查DBA_DATA_FILES和DBA_FREE_SPACE,结果只反映当前容器。如果CDB里有5个PDB,就要登5遍、跑5次脚本,效率太低。

我一般备用一条基于CDB视图的汇总查询,一条SQL扫完所有容器:

SELECT c.name AS container_name, t.name AS tablespace_name, t.contents AS type, d.file_name, ROUND(d.bytes / 1024 / 1024 / 1024, 2) AS allocated_gb, ROUND((d.bytes - NVL(f.bytes, 0)) / 1024 / 1024 / 1024, 2) AS used_gb, ROUND((d.bytes - NVL(f.bytes, 0)) / NULLIF(d.bytes, 0) * 100, 1) AS used_pct, d.autoextensible, ROUND(d.maxbytes / 1024 / 1024 / 1024, 2) AS max_gb FROM cdb_data_files d JOIN cdb_tablespaces t ON d.tablespace_name = t.tablespace_name AND d.con_id = t.con_id JOIN v$containers c ON d.con_id = c.con_id LEFT JOIN ( SELECT con_id, file_id, SUM(bytes) AS bytes FROM cdb_free_space GROUP BY con_id, file_id ) f ON d.con_id = f.con_id AND d.file_id = f.file_id ORDER BY c.name, t.name, d.file_name;

执行的结果会列出每个容器、每个表空间的分配大小、已用大小、使用率、是否自动扩展、最大上限。哪个PDB的哪个表空间快满了,一眼就能看到。

这条SQL特别适合定时巡检,也适合在接到告警时先快速判断:是真的数据文件满了,还是因为MAXSIZE设太小被顶住了,还是磁盘物理空间不足。

4.2 告警常见三种情况

接到表空间使用率告警,不要急着加数据文件,先分清楚是哪种情况:

  • 使用率超过90%,但文件仍可自动扩展:这种最省事,通常只是增长较快,需要评估要不要调高MAXSIZE,或者加新的数据文件。
  • 使用率接近100%,且MAXSIZE已经触顶:说明单文件上限被卡住了,需要执行ALTER DATABASE DATAFILE ... RESIZE或者ALTER TABLESPACE ... ADD DATAFILE。
  • 使用率不高,但磁盘分区满了:这是CDB环境里容易被忽略的一点。多个PDB可能共享同一个挂载点,某一个PDB临时表空间暴涨,可能把整个共享盘打满,进而影响所有PDB。收告警时我习惯同步执行一次df -h,把文件系统和数据库视图放在一起看,避免只盯着表空间百分比却忽略了宿主文件系统容量。

4.3 应急扩容操作示例

确认需要扩容后,常见操作按照场景区分:

如果只是想放宽单个数据文件的上限:

ALTER DATABASE DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/ts_app01.dbf' AUTOEXTEND ON NEXT 1G MAXSIZE 64G;

或直接调整现有文件大小(注意该文件当前使用量必须小于目标大小):

ALTER DATABASE DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/ts_app01.dbf' RESIZE 40G;

如果需要增加一个全新的数据文件,注意切换到正确的容器再执行:

ALTER TABLESPACE ts_app ADD DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/ts_app02.dbf' SIZE 20G AUTOEXTEND ON NEXT 1G MAXSIZE 64G;

这里有一个很实际的经验:扩容前先查V$SESSION里有没有长时间占用的会话,做过大事务或大量排序的业务。因为ALTER DATABASE DATAFILE ... RESIZE这类操作虽然本身很快,但如果在业务高峰执行,可能遇到文件系统锁、空间分配不足等问题。最好放在低峰期操作,并且操作完立刻跑一次使用率SQL确认新容量已经生效。

4.4 缩容和回收碎片的边界

删了很多数据后,表空间使用率下降,但文件大小没变,这是正常现象:数据文件不会因为删了数据而自动收缩。回收空间有两类手段,边界要搞清楚:

第一类是合并碎片,命令简单但效果有限:

ALTER TABLESPACE ts_app COALESCE;

COALESCE只能合并相邻的空闲区,对本地管理表空间来说作用已经很小,因为区分配本身就是动态管理。它不会释放任何数据文件。

第二类是真正收缩数据文件大小。12c里可以对表空间执行SHRINK SPACE:

ALTER TABLESPACE ts_app SHRINK SPACE KEEP 10G;

KEEP参数表示保留目标大小。执行时Oracle会尝试把空闲区回收并压缩文件。这个方法不见得总是有效:如果某个段(比如一个大表或大索引)占据了文件的后半部分,而段本身无法移动,收缩就会中途停下,或者收缩效果很有限。真正彻底的场景还是重建表空间:新建一个表空间,把数据搬过去,切换业务,再删旧表空间。对在线业务来说,这个过程往往需要停机窗口,不是一句SQL能搞定的。

所以我对缩容的总体心得是:规划大于事后治理。建表空间时宁可把初始文件设大一点、自动扩展策略设合理一点,也不要靠事后收缩来硬撑。缩容操作费时费力,且有风险。

5. 容易翻车的UNDO和TEMP:容器级特殊表空间的坑

5.1 本地UNDO模式下每个PDB管理各自的UNDO表空间

12c多租户架构默认采用本地UNDO模式,每个PDB都有自己的UNDO表空间,而不是像Non-CDB那样实例级共享一个UNDO。也就是说,在PDB里查V$UNDO_TABLESPACE看到的内容,只属于当前PDB。

这个设计本身合理,但带来一个管理上的坑:很多习惯老经验的人,都喜欢在一个会话里查看“全局”的UNDO空间。查询结果里出现多个同名的UNDOTBS1,因为每个容器都各自维护一个。如果搞混了容器,会看到一个明明没怎么使用的UNDO表空间,另一个PDB里的UNDO却快满了。

查看当前容器UNDO的配置,最直接的方式是:

ALTER SESSION SET CONTAINER = pdb1; SHOW PARAMETER undo_tablespace;

输出会显示当前PDB的UNDO表空间名。如果想看所有容器的情况,可以直接查:

SELECT con_id, tablespace_name, contents FROM cdb_tablespaces WHERE contents = 'UNDO';

在本地UNDO模式下,每个PDB的UNDO表空间可以由PDB内的DBA自行管理,比如扩容:

ALTER TABLESPACE undotbs1 ADD DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/undo_pdb1_02.dbf' SIZE 8G AUTOEXTEND ON NEXT 512M MAXSIZE 16G;

还要注意一点:UNDO表空间创建时的标准写法是:

CREATE UNDO TABLESPACE undo_pdb1 DATAFILE '/u01/app/oracle/oradata/ORCL/PDB1/undo_pdb1_01.dbf' SIZE 8G;

如果切换PDB的默认UNDO表空间,流程是:先创建新的UNDO表空间,然后执行:

ALTER SYSTEM SET undo_tablespace = undo_pdb1 SCOPE = BOTH;

切换后旧的UNDO表空间不立即删除,而是要等症状中的事务提交完成后,再考虑使用DROP TABLESPACE,否则容易因为存在活动回滚段导致删除失败。这是很常见的翻车点。

5.2 临时表空间在CDB/PDB里的真实面貌

临时表空间向来容易出问题,CDB架构下更容易混淆。先说视图层面:CDB_TABLESPACES里CONTENTS字段等于TEMPORARY的就是临时表空间。一个PDB可以有自己的默认临时表空间,而根容器也有自己的。

临时表空间的典型报错场景是排序或临时LOB操作过多,比如大量并行查询、大数据量GROUP BY。这时候临时表空间会飞速增长。检查当前PDB默认临时表空间:

ALTER SESSION SET CONTAINER = pdb1; SELECT * FROM database_properties WHERE property_name = 'DEFAULT_TEMP_TABLESPACE';

创建新临时表空间:

CREATE TEMPORARY TABLESPACE temp_pdb1 TEMPFILE '/u01/app/oracle/oradata/ORCL/PDB1/temp_pdb1_01.dbf' SIZE 8G AUTOEXTEND ON NEXT 1G MAXSIZE 32G;

然后切换默认临时表空间:

ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp_pdb1;

临时表空间使用率报警时,很多人容易误判为业务数据表空间紧张。我建议告警处理时一定要先区分表空间类型,看到CONTENTS='TEMPORARY'就走另一套思路:查V$TEMPSEG_USAGE定位占用临时空间的SQL,再判断是否需要调整SQL或者扩容临时文件,而不是盲目往数据表空间里加文件。

5.3 切换UNDO表空间的正确方法

刚才简单提了切换UNDO表空间,这里展开一下流程,因为很多人会忽略“旧UNDO表空间不能马上删”这一点:

  1. 确认当前UNDO表空间:
    ALTER SESSION SET CONTAINER = pdb1; SHOW PARAMETER undo_tablespace;
  2. 创建新UNDO表空间,大小参考当前峰值使用量。
  3. 执行ALTER SYSTEM SET undo_tablespace = undo_pdb1 SCOPE = BOTH;
  4. 等待一段时间,观察新UNDO表空间是否正常工作。
  5. 旧UNDO表空间暂时保留,确认没有报错和回滚段冲突后,再执行DROP TABLESPACE undotbs1 INCLUDING CONTENTS AND DATAFILES;

我的实际经验是:切换后至少要观察一个业务高峰期再删旧文件,稳妥起见保留两三天也不为过。UNDO这种东西一旦出问题,轻则ORA-01555,重则影响整个实例的一致性读,最好不要贪图省事。

6. 表空间迁移与PDB整体把玩:从管理一个库变成管理整个容器

6.1 为什么迁移单位从表空间变成了PDB

老版本数据库迁移,通常在实例层面做表空间传输、数据泵导入导出,需要仔细处理表空间、用户、权限、序列等一堆对象。12c下这个问题反而被简化了:PDB整体就相当于一个完整的小数据库,里面包含了它的所有表空间、用户、数据、元数据。迁移的粒度从“表空间”提升到了“PDB”,操作单位完全不同。

比如从一套环境把pdb1整体搬走,主流方法是unplug/plug:

-- 源端:关闭PDB并分离 ALTER PLUGGABLE DATABASE pdb1 CLOSE; ALTER PLUGGABLE DATABASE pdb1 UNPLUG INTO '/backup/pdb1.xml'; -- 目标端:基于XML加入CDB CREATE PLUGGABLE DATABASE pdb1 USING '/backup/pdb1.xml' COPY; ALTER PLUGGABLE DATABASE pdb1 OPEN;

这个过程中,整个PDB的所有表空间会随之迁移,包括数据文件、临时表空间、UNDO表空间(在本地UNDO模式下)。相比以前逐个表空间做TRANSPORTABLE TABLESPACE,可操作性提升了一大截。

当然,unplug/plug有版本和平台限制,跨平台一般还是走数据泵。但即便走数据泵,在目标端导入时,通常也是先把PDB建好,再在PDB里创建目标表空间。这样一来,表空间的管理逻辑始终与某个PDB绑定在一起,而不是与全局实例绑定。

6.2 unplug / plug / impdp中表空间的处理

用数据泵(expdp/impdp)迁移PDB里的用户数据时,表空间处理要注意两点:

  • 导出时:SCHEMAS方式导出会带上对象的表空间属性,即使目标库表空间名不同,导入时也会尽量映射。如果目标PDB里还没有同名表空间,impdp会尝试自动创建,但路径、大小取决于目标环境的OMF配置,不一定完全符合预期。
  • 导入时:建议先用impdp的SQLFILE参数生成导入脚本,检查里面CREATE TABLESPACE语句是否符合目标环境的路径规划,再决定是修改脚本还是让impdp自动处理。

我遇到过一个比较典型的坑:原来表空间数据文件路径只存在于源端某套存储,目标端挂载点结构完全不同。如果直接impdp,默认会产生一个与源端路径一致的数据文件,导致目标PDB使用错误路径或失败。解决办法是先手动在目标PDB里创建好表空间,然后impdp时通过REMAP_TABLESPACE映射:

impdp directory=DATA_PUMP_DIR dumpfile=pdb1.dmp \ schemas=app_user \ remap_tablespace=ts_app:ts_app_new \ transform=segment_attributes:none

这里remap_tablespace=ts_app:ts_app_new把源端的表空间名映射到目标端新表空间名。transform=segment_attributes:none则是让段对象重新适用目标表空间的存储属性,避免把源端的存储参数带过来产生冲突。

6.3 团队协作的分工建议

CDB环境一旦有多个PDB,管理职责也需要随之调整。过去一个DBA负责整个实例的所有表空间;12c里更合理的方式是按PDB划分责任。每个PDB有自己的管理员,可以管理自己容器内的表空间,但不能干涉根容器和其他PDB。根容器的表空间空间管理仍然由超级DBA统一负责。

实际协作中有个容易踩的权限坑:某人拿着DBA角色在PDB里执行CREATE TABLESPACE可能提示权限不足,因为很多对象权限在12c里被区分为公共权限(Common Privilege)和本地权限(Local Privilege)。如果一个权限是以公共权限方式授予的,在特定PDB中可能被撤销或限制。遇到这种情况,不要直接用GRANT DBA TO ...这种老办法去“暴力解决”,而是在根容器或PDB里检查DBA_SYS_PRIVS、ROLE_TAB_PRIVS,确认具体缺的是哪个权限,再最小化补齐。这样既能解决问题,也不至于把容器间的权限边界搞得一团乱。

7. 给接手CDB表空间管理的几点个人经验

7.1 永远先看CON_NAME,再执行任何DDL

无论你是老手还是刚接触12c,每次登录数据库后,请养成一条肌肉记忆:

SELECT SYS_CONTEXT('USERENV','CON_NAME') FROM dual;

然后把这条命令的输出作为所有后续操作的前提。我在多个项目里都见过类似的教训:不是技术不行,而是习惯性地用老经验直接执行脚本,结果在根容器里建了业务表空间,或者在PDB里尝试修改根容器的表空间。一条CON_NAME就能避免。

7.2 给表空间命名和数据文件路径建立统一规范

CDB里多个PDB允许同名表空间,但不能依赖这一点。万一交接、迁移、恢复时搞混了PDB,同名表空间会造成很大的排查成本。我建议在表空间命名上直接带PDB标识,比如:

  • 表空间:ts_app_pdb1
  • 数据文件:ts_app_pdb1_01.dbf
  • 临时表空间:temp_pdb1
  • UNDO表空间:undo_pdb1

这样从名字上就能知道是哪个PDB的,也能在CDB_DATA_FILES里快速过滤。

7.3 留一套“表空间速查”脚本,关键时刻不慌

维护CDB表空间,我一般会在每台数据库服务器上留一组常用SQL脚本:

  • 表空间整体视图:cdb_tablespaces+cdb_data_files汇总;
  • 容器信息:v$containers;
  • 当前会话容器:SYS_CONTEXT('USERENV','CON_NAME');
  • 临时段占用:v$tempseg_usage。

脚本本身不长,但遇到事故时能省下大量手敲命令的时间。尤其是多个PDB一起告警的时候,一套脚本把所有容器的状态打出来,比逐个人肉切换容器高效太多。

7.4 从个人体会谈12c表空间管理的整体感受

带了一些项目之后,我越来越觉得CDB表空间管理的核心,其实不在于CREATE TABLESPACE的那条SQL怎么写,而在于是否建立了“容器边界”意识。表空间是容器内部的资源,不是实例全局的资源。理解了这一点,后面所有操作都是顺理成章的事。

另外要提醒的是,Oracle版本迭代很快,12c之后又有19c、21c等更新版本,但CDB的基础逻辑是一脉相承的。把12c这套表空间管理机制理清楚,后续版本里的“容器—表空间—数据文件”三层关系就不会再绕晕。

如果不确定某个PDB里表空间的实际归属,最简单的方法还是回到最基础的那条SQL:

SELECT con_id, tablespace_name, file_name, bytes/1024/1024/1024 AS size_gb FROM cdb_data_files ORDER BY con_id, tablespace_name;

把结果拉出来,对着v$containers里的容器名一比对,很多疑惑瞬间就散了。这也算是我接手CDB表空间管理以来,最想分享给大家的一条实战心得。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 15:16:00

ppt-master:基于Python的代码驱动PPT自动化生成引擎

1. 项目概述:这不是一个PPT模板库,而是一套可编程的幻灯片生成引擎“ppt-master”这个名字乍一听像某个网红PPT资源站,但实际接触过的人很快会发现——它根本不是传统意义上的模板合集。我第一次在某技术社区看到这个词时,正被三个…

作者头像 李华
网站建设 2026/10/20 15:15:20

科研基金申报技术路线图制作全攻略:从PPT模板到Word排版避坑指南

做科研基金申报书的时候,最容易被人忽略的,其实是技术路线图。我见过太多申报人把精力全砸在正文措辞上,最后随手扔一张思维导图上去,结果评审专家在前面几页就把印象分丢了。今天这篇就把技术路线图从设计逻辑、配色参数、PPT模板…

作者头像 李华
网站建设 2026/10/20 15:15:12

FDE前置部署工程师实战指南:从进场调研到交付落地的完整方法论

1. 这个岗位到底在解决什么问题第一次听到“FDE”这个缩写的时候,我脑子里蹦出来的是“Front-end Development Engineer”,前端开发工程师。后来跟几个做企业服务的同行聊深了才搞明白,在解决方案交付这个圈子里,FDE指的是Field D…

作者头像 李华
网站建设 2026/10/20 15:14:53

机器学习预测裂缝扩展:从物理特征到工程落地实践

这几年只要涉及结构健康监测、材料疲劳或者断裂力学的场景,我基本都会遇到“机器学习预测裂缝扩展”这个题目。它听起来很唬人,但拆开看其实是一个很典型的工程问题:我们手里有材料属性、载荷条件、几何形状,甚至历史监测数据&…

作者头像 李华
网站建设 2026/10/20 15:14:29

基于Spark和Hadoop的房屋推荐系统:ALS协同过滤与特征工程实战

房子推荐这种事,听起来不像技术活,但真被大数据磨过一遍,你会发现里面的坑比想象中多。这个"spark hadoop python房屋推荐系统"不是什么花哨的 Demo,而是一条从海量行为日志里挖用户偏好、再用算法把合适房源推到面前的…

作者头像 李华
网站建设 2026/10/20 15:14:21

Linux内存去哪了?free命令与进程占用排查实战

1. 内存都去哪了:一个让运维人半夜惊醒的经典问题 你有没有遇到过这种场景:登录一台Linux服务器,随手敲一个 free -h ,发现可用物理内存只剩几百兆甚至几十兆,第一反应是“哪个进程在吃内存”,于是 ps a…

作者头像 李华