执行 alter tablespace read only 前必须确认:①无未提交事务(v$transaction 为空);②无活跃 dml 会话(v$session 中 status='active' 且 sql_id 非空者为空);③数据库处于归档模式(archive log list 显示 archive mode)且表空间为 permanent 类型。
执行 alter tablespace read only 前必须确认的三件事
这条语句不是“一敲就生效”的安全操作,它会立刻阻断所有写入,一旦出错可能卡住业务。核心前提是:表空间里不能有未提交的事务、不能有活动的 dml 会话、且必须处于归档日志模式(如果是 oracle)。
-
SELECT * FROM V$TRANSACTION和SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE' AND SQL_ID IS NOT NULL必须返回空——否则强制只读后,这些会话会 hang 住甚至报ORA-01642: begin backup not active for tablespace类错误 - 检查是否开启归档:
ARCHIVE LOG LIST输出中需含Database log mode: Archive Mode;否则会直接报ORA-01123: cannot start online backup; media recovery not enabled - 确认表空间内无
TEMPORARY或UNDO类型的数据文件——READ ONLY只适用于PERMANENT表空间,对UNDOTBS1或TEMP执行会直接报ORA-03217: invalid option for alter of TEMPORARY tablespace
实际执行时为什么常卡在 “waiting for global enqueue”
这是最常见的挂起现象,本质是 Oracle 在做分布式锁协调:它要确保整个 RAC 环境(或单实例的后台进程)都达成一致,才能把表空间状态刷进数据字典。不是命令写错了,而是有其他会话正持有该表空间对象的 TM(DML)锁或 TX(事务)锁。
- 查谁在挡路:
SELECT sid, serial#, event, sql_id FROM V$SESSION WHERE event LIKE 'enq:%',重点关注event为enq: TS - contention或enq: TX - row lock contention的会话 - 别急着 kill,先用
SELECT OBJECT_NAME FROM DBA_OBJECTS WHERE OBJECT_ID IN (SELECT OBJECT_ID FROM V$LOCKED_OBJECT)看哪些对象被锁了,再决定是否终止源头会话 - 如果只是想快速验证语法,建议先在测试库用空表空间试:
CREATE TABLESPACE test_ro DATAFILE '/u01/oradata/test_ro01.dbf' SIZE 10M;,再执行ALTER TABLESPACE test_ro READ ONLY;
ALTER TABLESPACE ... READ ONLY 后的真实限制边界
只读 ≠ 完全冻结。Oracle 允许某些元数据变更继续发生,但应用层感知不到这些“例外”,容易误判权限或逻辑。
- 允许的操作:
DROP表(删的是数据字典记录,不碰数据文件)、TRUNCATE会报错(因为要清数据块),但ALTER TABLE ... DROP COLUMN在 12c+ 可能成功(依赖COMPATIBLE参数) - 禁止的操作:任何
INSERT/UPDATE/DELETE、CREATE INDEX、ALTER TABLE ... ADD COLUMN,连ANALYZE TABLE都会触发ORA-00372: file 5 cannot be modified at this time - 特别注意:
SELECT FOR UPDATE仍可执行(锁信息存在内存),但后续UPDATE一定失败;这个细节常被开发忽略,导致“能查能锁却不能改”的困惑
怎么安全地切回读写?别只记 READ WRITE
反向操作看似简单,但若之前有异常中断(比如 ALTER 被 kill),表空间可能卡在中间状态,直接 ALTER TABLESPACE ... READ WRITE 会报 ORA-01138: database must be mounted and not open or open read-only。
- 先确认状态:
SELECT TABLESPACE_NAME, STATUS FROM DBA_TABLESPACES WHERE STATUS = 'READ ONLY';—— 如果查不到,说明已恢复,不用动 - 如果状态是
READ ONLY却执行失败,大概率是控制文件没同步,此时需重启数据库(非 force)再试;不推荐用RECOVER TABLESPACE强行修复,风险高 - 生产环境建议加超时控制:在脚本里用
sqlplus -S / as sysdba 包裹,并设置 <code>SET TIMEDOUT 30,避免无限等待
真正麻烦的从来不是命令本身,而是它背后牵扯的事务一致性、RAC 锁协调和归档依赖——这些点漏掉一个,READ ONLY 就从保护手段变成故障入口。










