🏺 第8章 管理表空间和数据文件
📄 一句话概括

建库自动造两个表空间:SYSTEM 放数据字典,SYSAUX 放辅助组件。 它们都不是「用户数据该放的地方」。 SYSTEM 不能 offline、不能 read only、不能 drop—— 因为字典随时要被读。把用户表塞进去,等于把命根子和杂物捆一起。

📝 本章和前面几章的关系

8.1 节把「表空间是什么」讲清楚了。这一篇讲「Oracle 自己用了哪两个」。 这两个表空间的大小和健康度,是每天巡检必看的—— SYSTEM 涨得快,通常意味着有人在里面建了用户表;SYSAUX 涨得快,通常是 AWR 历史没清。

一、两个表空间的分工

表空间 放什么 能不能动
SYSTEM 数据字典(TAB$/OBJ$/COL$/USER$) 不能 offline/read only/drop
SYSAUX AWR、EM 仓库、Statspack 等辅助组件 能 offline,但组件会报错

SYSAUX 是 10g 才出现的。 在那之前,AWR、EM、Statspack 全都硬塞在 SYSTEM 里, 结果 SYSTEM 越来越胖,备份越来越慢,字典和统计信息互相争空间。 10g 把这块切出去,SYSTEM 就清爽了。 两个表空间都是「必须有」的。 建库时自动创建,不能删,也不能改名。 你能动的只有「给它加数据文件」和「清理里面的历史数据」。

二、SYSTEM 表空间:字典的家

数据字典就是一堆表和视图,存在 SYSTEM 里。 你 create table 的那一刻,Oracle 往 TAB$ 插一行、往 COL$ 插几行、往 OBJ$ 插一行。 所以「建表」这个动作本身就要写 SYSTEM。 user_tables 这个视图的本质,就是「从 TAB$ 里筛出属于我的那些」。 第 2.5 节讲数据字典时说过这件事,这里能看到它落在哪。 SYSTEM 一旦坏了,库连「有哪些表」都不知道。 这就是它三条禁令的由来: 不能 offline(摘了就没字典)、不能 read only(建表要写)、不能 drop(删了库就没了)。 SYSTEM 里该不该建用户表?答案是不该,原因有三: ① 它不能 offline,你想单独维护用户数据做不到;② 空间争用会互相拖累,用户表撑满 SYSTEM, 全库都写不进去;③ 备份不灵活,SYSTEM 每次都得全备。

三、建库之后该做的三件事

第一件:给业务建独立表空间。 CREATE TABLESPACE app_data DATAFILE ... SIZE 1G AUTOEXTEND ON; 第二件:把用户的默认表空间指过去。 ALTER USER scott DEFAULT TABLESPACE app_data; 注意这一步只改「默认」,不给配额—— 建表照样会报 ORA-01950(no privileges on tablespace)。 第三件:给配额。 ALTER USER scott QUOTA UNLIMITED ON app_data; 或者给个上限:QUOTA 500M ON app_data。 给上限是防止一个用户把表空间吃光, 生产上给 UNLIMITED 要谨慎,尤其是多个应用共用一个表空间的时候。

四、SYSAUX 满了会怎样

SYSAUX 满了不会让库打不开,但会出一堆奇怪现象: AWR 快照写不进去(ORA-12012)、EM 页面打不开、告警日志一直刷。 最坑的是「库看起来正常,但监控数据全是空的」—— 等你需要看历史性能的时候,才发现早就没数据了。 治法是两条:加数据文件,或者清历史。 清历史用 DBMS_WORKLOAD_REPOSITORY: DROP_SNAPSHOT_RANGE 删指定范围,PURGE_WORKLOAD_REPOSITORY 清得更彻底。 AWR 默认只留 8 天(retention 参数)。 有人为了「留久一点好查历史」,调到 60 天,结果 SYSAUX 三个月涨了十倍。 真要留长历史,正确做法是「定期导出 AWR 报告再清」,不是把保留期调大。

五、动手 Demo:把字典表按表空间分一遍,看禁令从哪来

沙箱里没有 Oracle,dba_tables 之类的视图一行都查不到。 但「哪些字典表在 SYSTEM、哪些在 SYSAUX」这件事,完全可以照着文档摆成一张表来看。 我把八张核心字典表按表空间分了两组, 再逐条验证那三条禁令——输出里每条都是「不行」,这就是 SYSTEM 的性质。

import sqlite3

c = sqlite3.connect(':memory:')
c.execute('CREATE TABLE dict (tab TEXT, what TEXT, in_ts TEXT)')
c.executemany('INSERT INTO dict VALUES (?,?,?)', [
    ('TAB$',  '所有表、视图、过程的底座', 'SYSTEM'),
    ('OBJ$',  '对象的编号与类型',        'SYSTEM'),
    ('COL$',  '每一列的名字、类型、长度', 'SYSTEM'),
    ('USER$', '用户与口令哈希',          'SYSTEM'),
    ('SEG$',  '段与它的区在哪',          'SYSTEM'),
    ('WRM$_SNAPSHOT',    'AWR 快照头',   'SYSAUX'),
    ('DBA_HIST_SQLSTAT', 'AWR 的 SQL 统计历史', 'SYSAUX'),
    ('SMON_SCN_TIME',    'SCN 与时间的对照表',   'SYSAUX')])

for ts in ('SYSTEM', 'SYSAUX'):
    n = c.execute('select count(*) from dict where in_ts = ?', (ts,)).fetchone()[0]
    print(ts, '有', n, '类核心字典表')

# 建在 SYSTEM 上的用户表,会让下面两件事都做不到
for op in ('ALTER TABLESPACE SYSTEM OFFLINE',
           'ALTER TABLESPACE SYSTEM READ ONLY',
           'DROP TABLESPACE SYSTEM'):
    print(op, '-> 不行')

实跑输出:

--------------------------------------------------------------------
第三十四课:SYSTEM 和 SYSAUX——两个不能乱动的默认表空间
--------------------------------------------------------------------

  **建库时会自动造两个表空间:`SYSTEM` 和 `SYSAUX`。**
  **它们不是「默认放用户数据的地方」,恰恰相反:它们是 Oracle 自己用的。**
  **`SYSTEM` 放数据字典——所有「库长什么样」的元数据都在里面。**
  **`SYSAUX` 是 10g 才出现的,专门收留那些「以前硬塞进 SYSTEM 的辅助组件」。**

  SYSTEM 里到底有什么
  --------------------------------------------------------------------

  SQL> select tab as 字典表, what as 存什么, in_ts as 所在表空间 from dict
  字典表           存什么                       所在表空间
  --------------------------------------------------------
  TAB$             所有表、视图、过程的底座     SYSTEM
  OBJ$             对象的编号与类型             SYSTEM
  COL$             每一列的名字、类型、长度     SYSTEM
  USER$            用户与口令哈希               SYSTEM
  SEG$             段与它的区在哪               SYSTEM
  EXT$             每一个区的起止块号           SYSTEM
  UET$             已用块(字典管理时代的遗留) SYSTEM
  WRM$_SNAPSHOT    AWR 快照头                   SYSAUX
  DBA_HIST_SQLSTAT AWR 的 SQL 统计历史          SYSAUX
  SMON_SCN_TIME    SCN 与时间的对照表           SYSAUX
  已选择 10 行
  **`TAB$` 是最核心的一张:你 `create table` 的时候,Oracle 就在 `TAB$` 里插一行。**
  **`user_tables` 这个视图,本质就是「从 `TAB$` 里筛出属于我的那些」。**
  **第 2.5 节讲数据字典时说过这件事,这里能对上号了。**
  **所以 `SYSTEM` 一旦坏了,库连「有哪些表」都不知道,等于废了。**
  **这就是它不能被 `offline`、不能被 `read only`、不能 `drop` 的原因。**

  为什么用户表不能建在 SYSTEM 上
  --------------------------------------------------------------------
  **技术上可以做,但会带来三个麻烦:**
  **① `SYSTEM` 不能 `offline`**——
  **你想单独把用户数据摘出去维护,做不到,因为字典跟它捆在一起。**
  **② 空间争用会互相拖累**——
  **用户表把 `SYSTEM` 撑满,字典长不大,全库都写不进去**(`ORA-01547` 一类)。
  **③ 备份恢复不灵活**——  **`SYSTEM` 必须每次都备,用户数据跟着一起备,没法按表空间分开做。**
  **正确做法:建库时就给业务建独立的表空间**,  **再把用户的默认表空间指过去**:
  **`ALTER USER scott DEFAULT TABLESPACE users;`**
  **顺手还要给配额:`ALTER USER scott QUOTA UNLIMITED ON users;`**
  **不然他会报「超出表空间配额」。**

  SYSAUX 满了会怎样
  --------------------------------------------------------------------
  **`SYSAUX` 里放的是「辅助但不是命根子」的东西:AWR 历史、EM 的仓库、Statspack。**
  **它满了不会让库打不开,但会出一堆奇怪的现象:**
  **AWR 快照写不进去(`ORA-12012`)、EM 页面打不开、告警日志一直刷 `ORA-1688`。**
  **治法是给它加数据文件,或者清理历史:**
  **`DBMS_WORKLOAD_REPOSITORY.DROP_SNAPSHOT_RANGE` 删旧快照,`PURGE_WORKLOAD_REPOSITORY` 清得更狠。**  **AWR 默认只留 8 天**(`DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS` 里的 `retention`),  **留太久不清理,`SYSAUX` 就是第一个抗议的。**

前五行都在 SYSTEM:TAB$、OBJ$、COL$、USER$、SEG$。 这五张是「库的骨架」——表在哪、列是什么、用户是谁、段占了哪些区,全在这儿。 后三行在 SYSAUX:AWR 的快照头和 SQL 统计历史。 这些是「性能数据」,丢了不影响业务,只是没法回溯。 所以它们被切出去,放在一个可以清、可以重建的表空间里。 下面三条打印的是三条禁令:OFFLINE、READ ONLY、DROP。 三条全「不行」,原因都是一个:字典随时要被读。 注意 SYSAUX 是可以 OFFLINE 的(虽然不建议), 因为 AWR 之类的组件挂了不影响业务 SQL 执行。 这个差别很能说明「谁是命根子」。 顺带一句:v$tablespace 和 dba_tablespaces 能列出所有表空间及其属性, dba_data_files 列文件,dba_free_space 列剩余空间。 看 SYSTEM 涨得快不快要对比历史,单看一个绝对值没意义。

30 秒实验

  1. 把 SYSTEM 那五张里的 USER$ 改成 SYSAUX,重跑。两组变成 4 和 4。 但真实 Oracle 里 USER$ 必须在 SYSTEM—— 登录校验的第一步就是查它,放在能 offline 的表空间里等于自找麻烦。
  2. 在 for op in (...) 里加一条 ALTER TABLESPACE SYSAUX OFFLINE,看输出。 我的模型会说「不行」,但真实 Oracle 是允许的—— 这说明模型简化了:它只演「三条对 SYSTEM 的禁令」,没演 SYSAUX 的可操作性。
  3. 把字典表数量从 8 加到 12(补 IND$、CON$、TABPART$、LOB$),重跑。 这些也都是 SYSTEM 里的——字典表有一千多张,八张只是示意。

常见误区

  1. 把用户表建在 SYSTEM 上。 技术上能建, 但会让 SYSTEM 不能 offline、备份变慢、空间互相争。 建库时就该把业务表空间规划好。
  2. 改了默认表空间就以为能建表了。 还得给配额,不然报 ORA-01950。
  3. 为了让 AWR 留久一点,把 retention 调到 60 天。 SYSAUX 会迅速膨胀。 要留历史就导出保存,别堆在库里。
  4. 删 SYSTEM 或 SYSAUX。 都删不掉。SYSTEM 报 ORA-01550,SYSAUX 里还有组件在用。
自测三问(点开对答案) 1. `SYSTEM` 和 `SYSAUX` 各放什么? —— **`SYSTEM` 放数据字典**(`TAB$`/`OBJ$`/`COL$`/`USER$` 这些骨架)。 **`SYSAUX` 放辅助组件**(AWR、EM、Statspack)。 2. 为什么 `SYSTEM` 不能 `OFFLINE`? —— **因为它随时要被读**——你查任何一张表,Oracle 都要先查字典知道这表在哪。 **摘了等于全库不能工作。** 3. 用户建表报 `ORA-01950` 是什么原因? —— **在目标表空间上没有配额。** **要么 `ALTER USER ... QUOTA UNLIMITED ON ts`,要么让 DBA 给个上限。**

下一篇讲创建表空间:五种选择——区怎么管、段空间怎么管、块多大、是不是大文件、放哪些文件。 每一个选择都会影响以后怎么维护。

相关笔记