四类操作天天用:改状态(read only/offline)、改默认、改名、删除扩容。
两个最容易踩的坑:READ ONLY 之后写报的是 ORA-00372(听着像磁盘问题);
DROP ... INCLUDING CONTENTS 删完磁盘不变——文件还在。
8.3 讲怎么建。这一篇讲建完之后怎么管。
日常 DBA 花在维护上的时间,比在建表空间上多得多。
这一篇有两条和后面连着:
READ ONLY 是报表库、历史库的常用手段;
OFFLINE 是「单独维护一个表空间」的前提,第 16 章做部分恢复时要用。
一、四种状态:能读能写不一样
| 状态 | 能读 | 能写 | 什么时候用 |
|---|---|---|---|
ONLINE |
能 | 能 | 正常 |
READ ONLY |
能 | 不能 | 报表库、历史数据 |
OFFLINE |
不能 | 不能 | 维护时摘出去 |
OFFLINE IMMEDIATE |
不能 | 不能 | 急着摘,不等检查点 |
READ ONLY 之后写会报 ORA-00372(file cannot be modified at this time)。
这个错很迷惑——它说的是「文件现在不能改」,不是「表空间只读」,
第一次见的人常以为是磁盘权限或者文件系统只读。
OFFLINE 之后读会报 ORA-00376(file cannot be read at this time)。
这两个码的区别值得记:一个说「不能改」,一个说「不能读」,对应的状态一个是 READ ONLY,
一个是 OFFLINE。
SYSTEM 表空间不能 OFFLINE、不能 READ ONLY。
因为它随时要被读(字典)。
UNDO 表空间也不能随便 OFFLINE——正在跑的事务需要它。
二、设置默认表空间:两级,还要配配额
两级默认:数据库级和用户级。
用户没单独指定时,用数据库级的那个。
ALTER DATABASE DEFAULT TABLESPACE app_data;
ALTER USER scott DEFAULT TABLESPACE app_data;
改了默认不等于给了配额。
用户在新表空间上没有配额,建表照样失败(ORA-01950)。
所以要成对做:ALTER USER scott QUOTA UNLIMITED ON app_data;
SYSTEM 不能当默认表空间。
想设成 SYSTEM 会被拦住——Oracle 干脆不让你把用户数据往字典里塞。
这个保护挺难得,很多数据库都没这种限制。
三、重命名:改表空间一句话,改文件路径要四步
改表空间名:ALTER TABLESPACE users RENAME TO app_data;
只改字典里的名字,物理文件一个字节都不动,几毫秒完事。
但要记得:脚本、监控、备份策略里写死的名字都得跟着改。
改数据文件的路径就麻烦多了,四步:
① ALTER TABLESPACE ts OFFLINE;(或把库起到 mount)
② 操作系统层 mv 文件
③ ALTER TABLESPACE ts RENAME DATAFILE '旧' TO '新';
④ ALTER TABLESPACE ts ONLINE;
顺序不能乱。
先 mv 后 offline 的话,offline 那一刻它要写文件头,找不到文件就报错。
这一点和 7.2 节改日志文件位置是同一个套路——
都是「先让对象停用,再动文件,再登记,再启用」。
四、删除:三档写法,破坏力递增
| 写法 | 删什么 | 磁盘会空出来吗 |
|---|---|---|
DROP TABLESPACE ts |
只删空表空间 | —(有东西就报错) |
... INCLUDING CONTENTS |
连段一起删 | 不会,文件还在 |
... INCLUDING CONTENTS AND DATAFILES |
连文件一起删 | 会 |
最容易踩的是中间那档:删完发现磁盘没少。
因为 INCLUDING CONTENTS 只清「库里的登记」,物理文件还躺在那儿。
得手工去操作系统删。
这和 7.2 节删日志组是同一个毛病。
还有个变体:... AND DATAFILES 在某些平台上也只是「标记可删」,
文件系统层面还会留一段时间。
所以删完记得去 ls 一眼,别只看视图。
SYSTEM 删不掉(ORA-01550)。
UNDO 和 TEMP 要用专门的语句,而且要先有替代品——
比如删 UNDO 之前得先切到另一个 undo 表空间。
五、维护数据文件:加、改、自动增长
三种扩法,各有适用场景:
| 做法 | 适合 | 注意 |
|---|---|---|
RESIZE 500M |
文件没到系统上限 | 只能改大不能改小(缩小要重建) |
ADD DATAFILE |
单文件到顶了 | 引入「区不能跨文件」的碎片 |
AUTOEXTEND ON |
想省心 | 一定给 MAXSIZE |
RESIZE 往小改一般会失败,因为文件尾部可能还存着数据。
要缩小得先 ALTER TABLE ... MOVE 把数据挪走,或者用 SHRINK。
ADD DATAFILE 是扩容最常用的手段,但它有副作用:
文件一多,「区不能跨文件」造成的碎片就多。
所以别一个 100MB 一个 100MB 地加,一次给足。
AUTOEXTEND 的 NEXT 也别设太小。
NEXT 10M 意味着写满一次就要等一次扩展——扩展是有开销的(要改文件头、更新控制文件)。
NEXT 100M 或 NEXT 1G 更省事,代价是可能多占一点空间。
六、动手 Demo:算一遍扩容账,看清三档删除的差别
沙箱里没有 Oracle,ALTER TABLESPACE 执行不了。
但「100MB 能装多少行」「长到 2GB 要长几回」这些账,是可以算准的。
我算了 100MB 的文件能装多少行,再算自动增长要长多少回,
最后把三档删除语句并排摆出来,指出哪一档磁盘不会空。
MB, ROWLEN = 1024 * 1024, 100
usable = 8192 - 100
per_blk = usable // ROWLEN
cur_mb, next_mb, max_mb = 100, 10, 2048
blocks = cur_mb * MB // 8192
print('%dMB = %d 个 8K 块,约 %d 行' % (cur_mb, blocks, blocks * per_blk))
# 自动增长的次数:从现在长到 2GB 要长多少回
grow = 0
size = cur_mb
while size < max_mb:
size = min(size + next_mb, max_mb)
grow += 1
print('每次长 %dMB,长到 %dMB 要长 %d 回' % (next_mb, max_mb, grow))
# 三档删除,破坏力递增
for sql in ('DROP TABLESPACE app_data',
'DROP TABLESPACE app_data INCLUDING CONTENTS',
'DROP TABLESPACE app_data INCLUDING CONTENTS AND DATAFILES'):
print(sql)
print('第二种删完磁盘不变——文件还在,得自己去操作系统删')
实跑输出:
--------------------------------------------------------------------
第三十六课:维护表空间——改状态、改名、删除、加文件
--------------------------------------------------------------------
**建完之后真正天天用的,是这一节的东西。** **状态、改名、删除、扩容,四类操作,每一类都有坑。**
四种状态,能干什么不一样
--------------------------------------------------------------------
SQL> select state as 状态, read as 读, write as 写, note as 说明 from st
状态 读 写 说明
----------------------------------------------------
ONLINE 能读 能写 正常状态
READ ONLY 能读 不能写 报表库、历史数据常用
OFFLINE 不能读 不能写 维护时临时摘出去
OFFLINE IMMEDIATE 不能读 不能写 不等检查点,立刻摘
已选择 4 行
**`READ ONLY` 之后写会报 `ORA-00372`(file cannot be modified at this time)。**
**注意这个错的表现很迷惑**:
**它说的是「文件现在不能改」,不是「表空间只读」**—— **第一次见的人常以为是磁盘权限问题。**
**`OFFLINE` 之后读会报 `ORA-00376`(file cannot be read at this time)。**
**`OFFLINE` 和 `OFFLINE IMMEDIATE` 的差别是「等不等检查点」:**
**前者会先把脏块刷完再摘,可能要等;后者立刻摘,脏块留在那儿。**
**急着停机维护用 `IMMEDIATE`,正常维护用普通的。**
**`SYSTEM` 表空间不能 `OFFLINE`、不能 `READ ONLY`。**
**因为它随时要被读(字典),摘了等于库废了。**
设置默认表空间:两级
--------------------------------------------------------------------
**两级默认:数据库级的默认表空间,和用户级的默认表空间。**
**用户没单独指定时,就用数据库级的那个。**
[Oracle 原码 · 本沙箱不执行]
| ALTER DATABASE DEFAULT TABLESPACE users;
| ALTER USER scott DEFAULT TABLESPACE users;
**一个常见的坑:改了默认表空间,不代表「配额」跟着给。**
**用户在新表空间上没有配额,建表照样失败**(`ORA-01950`:no privileges on tablespace)。
**所以要成对做:`ALTER USER scott QUOTA UNLIMITED ON users;`**
**另一个坑:`SYSTEM` 不能当默认表空间。** **想设成 `SYSTEM` 会报 `ORA-12914` 一类**——
**Oracle 干脆不让你把用户数据往字典里塞。**
重命名表空间:一句话
--------------------------------------------------------------------
[Oracle 原码 · 本沙箱不执行]
| ALTER TABLESPACE users RENAME TO app_data;
10g 起支持,只改名字不挪数据。
**改的是字典里的名字,物理文件一个字节都不动。** **所以这句很快,几毫秒就完事。**
**但要记得:所有脚本、监控、备份策略里写死的表空间名,都得跟着改。**
**改数据文件的路径就不一样了,那要动文件**,
**得先 `offline`(或把库起到 mount),再 `ALTER TABLESPACE ... RENAME DATAFILE ... TO ...`。**
**顺序不能乱**:先 `offline` → 操作系统 `mv` → `RENAME DATAFILE` 登记 → `online`。
**先 `mv` 后 `offline` 的话,`offline` 那一刻它要写文件头,找不到就报错。**
删除表空间:带不带那两个词差很多
--------------------------------------------------------------------
[Oracle 原码 · 本沙箱不执行]
| DROP TABLESPACE app_data INCLUDING CONTENTS AND DATAFILES;
不带 INCLUDING CONTENTS 就直接报错,除非表空间是空的。
**三档写法,破坏力递增:**
**`DROP TABLESPACE ts;`——只删空表空间,里面有东西就报 `ORA-01549`。**
**`... INCLUDING CONTENTS`——连里面的段一起删,但磁盘文件还在。**
**`... INCLUDING CONTENTS AND DATAFILES`——连文件也删,磁盘真的空出来。**
**最容易踩的是中间那档:删完发现磁盘没少。**
**因为 `INCLUDING CONTENTS` 只清「库里的登记」,物理文件还躺在那儿**,得手工去操作系统删。
**这和 7.2 节删日志组是同一个毛病。**
**`SYSTEM` 表空间删不掉,报 `ORA-01550`。** **`UNDO` 和 `TEMP` 要用专门的语句删**
(`DROP TABLESPACE ... INCLUDING CONTENTS AND DATAFILES` 对 temp 不行,
temp 要走 `DROP TABLESPACE ts INCLUDING DATAFILES` 且先切走默认)。
扩容:加文件、改大小、开自动增长
--------------------------------------------------------------------
**假设表空间现在 100MB,写满了。三种扩法:**
**① `ALTER DATABASE DATAFILE '...' RESIZE 500M;`**——
**直接把现有文件改大,最省事,但受文件系统单文件上限约束。**
**② `ALTER TABLESPACE ts ADD DATAFILE '...' SIZE 100M;`**——
**再加一个文件,能绕过单文件上限,但会引入「区不能跨文件」的碎片问题。**
**③ `ALTER DATABASE DATAFILE '...' AUTOEXTEND ON NEXT 10M MAXSIZE 2G;`**——
**让它自己长,省心,但要盯 `MAXSIZE`。**
**算一下 100MB 能装多少行:每块 80 行,100MB 是 12800 个块,约 13107 行。**
**所以一张一千万行的表,光数据就要 954MB 左右**——
**这还没算索引。**
**估算容量时按「行数 × 行长 × 1.3」粗算(含 `PCTFREE` 和块头开销),比拍脑袋强。**
第一行:100MB 等于 12800 个 8K 块,按每块 80 行算,约 102 万行。
记住「100MB 大约装一百万行(行长 100 字节)」这个数量级,估容量的时候很好用。
第二行:每次长 10MB,从 100MB 长到 2048MB 要长 195 回。
每回都要改文件头、更新控制文件——这就是 NEXT 别设太小的原因。
195 这个数还说明另一件事:MAXSIZE 2G 一旦长满,就再也不长了,接下来就是 ORA-01653。
所以 MAXSIZE 要给足,别按「现在够用」来设。
下面三行是三档删除语句。
第二档(INCLUDING CONTENTS)删完磁盘不变——
这是新手最常踩的坑:以为删干净了,结果 df 一看一点没少。
第三档(AND DATAFILES)才会真删文件。
但即使在第三档,也建议删完去 ls 一眼——有些平台上文件句柄要等进程退出才真正释放。
30 秒实验
- 把
ROWLEN从 100 改成 200,重跑。行数从 102 万降到 51 万。 行长翻倍,能装的行减半——这是估算容量最基本的直觉。 - 把
next_mb从 10 改成 100,重跑。增长次数从 195 降到 20。 少了九成——这就是「NEXT设大一点」的量化依据。 - 把
max_mb从 2048 改成 200,重跑。增长次数变成 10 次。MAXSIZE越小,越早撞上ORA-01653。
常见误区
DROP TABLESPACE ... INCLUDING CONTENTS之后以为磁盘空了。 不会,文件还在。 要加AND DATAFILES,或者手工删。READ ONLY之后看到ORA-00372以为是磁盘权限问题。 是表空间只读,不是磁盘只读。- 改数据文件路径时先
mv再offline。offline要写文件头,找不到文件就报错。 顺序是「先停用,再动文件」。 AUTOEXTEND ON NEXT 10M不给MAXSIZE。 能长到磁盘满,把同机别的服务一起拖死。
自测三问(点开对答案)
1. `READ ONLY` 和 `OFFLINE` 报的错有什么不同? —— **`READ ONLY` 写会报 `ORA-00372`(file cannot be modified)。** **`OFFLINE` 读会报 `ORA-00376`(file cannot be read)。** 2. 为什么 `DROP ... INCLUDING CONTENTS` 删完磁盘没变? —— **它只清库里的登记,不删物理文件。** **要加 `AND DATAFILES`,或者自己去操作系统删。** 3. 改数据文件路径的四步是什么? —— **`OFFLINE` → 操作系统 `mv` → `RENAME DATAFILE` → `ONLINE`。** **顺序不能乱,先 `mv` 会让 `OFFLINE` 失败。** 4. `ADD DATAFILE` 有什么副作用? —— **文件一多,「区不能跨文件」造成的碎片就多。** **所以别零碎地加,一次给足。**下一篇讲撤销表空间:回滚、读一致性、闪回查询,三件事都靠它。
ORA-01555 这个经典错误也会在这一篇算清楚。
- ☐ (本篇完,下一篇 8.5 管理撤销表空间)
相关笔记
- 管理撤销表空间
- 创建表空间
- 管理重做日志文件
-
- 🐬 MySQL必知必会/00-索引
- 🏺 Oracle从入门到精通 · 索引