如何重置损坏的临时表空间_不重启数据库下的TEMP替换法

2次阅读

TEMP表空间损坏时应先OFFLINE DROP损坏tempfile,再重建新临时表空间并切换默认设置,最后清理残留会话。直接DROP或仅添加新tempfile无效,重启也不能绕过控制文件中损坏元数据的校验。

TEMP 表空间损坏后 ALTER database TEMPFILE ... DROP INCLUDING DATAFILES 报错

oracle 临时表空间损坏时,常见现象是排序、哈希连接或全局临时表操作报 ora-01157(无法识别/锁定数据文件)或 ora-01110(具体文件路径)。此时想直接删掉坏的 tempfile,但执行 alter database tempfile '/path/to/temp01.dbf' drop including datafiles 往往失败——因为 oracle 要求该 tempfile 当前未被任何会话使用,而损坏的 tempfile 可能仍被标记为“活跃”,哪怕实际已不可读。

实操建议:

  • 先查哪些 session 正在用这个 tempfile:select sid, serial#, sql_id FROM v$session WHERE tempseg_size > 0;如果结果非空,ALTER SYSTEM KILL SESSION 'sid,serial#' 杀掉(注意:不是所有 session 都能安全杀,尤其应用连接池里的长连接)
  • 确认无活跃使用后,强制脱机再删:ALTER DATABASE TEMPFILE '/path/to/temp01.dbf' OFFLINE DROP(注意是 OFFLINE DROP,不是 DROP
  • OFFLINE DROP 不校验文件存在性,只更新控制文件元数据,所以能绕过 I/O 错误

重建 TEMP 表空间必须用 CREATE TEMPORARY TABLESPACE,不能只加 tempfile

有人试过跳过重建表空间,直接 ALTER TABLESPACE temp ADD TEMPFILE ...,结果发现新文件加进去了,但旧损坏的 tempfile 还卡在 DBA_TEMP_FILES 里显示 INVALID 状态,且部分 session 仍尝试访问它,导致间歇性报错。根本原因是 Oracle 的临时表空间结构不支持“原地修复”——损坏的 tempfile 元数据残留会干扰分配逻辑。

实操建议:

  • 新建一个干净的临时表空间:CREATE TEMPORARY TABLESPACE temp_new TEMPFILE '/u01/oradata/db/temp_new01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED
  • 切换默认临时表空间:ALTER DATABASE default TEMPORARY TABLESPACE temp_new
  • 确认切换生效:SELECT property_value FROM database_properties WHERE property_name = 'DEFAULT_TEMP_TABLESPACE'
  • temp 表空间此时可安全 DROP TABLESPACE temp INCLUDING CONTENTS AND DATAFILES(前提是已无 session 在用它)

为什么不能等数据库重启再处理?

重启看似一劳永逸,但很多生产库不允许停机,而且即使重启,损坏的 tempfile 若没从控制文件清理,实例启动时仍可能卡在验证阶段,或者启动后首次排序就触发 ORA-01157。更麻烦的是:如果损坏发生在 ASM 磁盘组或存储层,重启后问题照旧,只是把时间点往后推了。

实操建议:

  • 检查控制文件是否已记录损坏:SELECT file_name, status, enabled FROM dba_temp_files;若 status 是 INVALIDMISSING,说明控制文件元数据已异常,必须手动干预
  • 避免依赖 startup mount 后用 ALTER DATABASE DATAFILE ... OFFLINE DROP——那是给永久表空间的,对 tempfile 无效
  • 真正起效的只有 OFFLINE DROP(针对单个 tempfile)或重建整个表空间(推荐)

切换后仍有 session 报 ORA-1652 扩展失败

新 temp 表空间建好了,DEFAULT_TEMP_TABLESPACE 也改了,但某些老 session(尤其是 JDBC 连接池中复用的连接)仍试图在旧 temp 上分配空间,报 ORA-1652: unable to extend temp segment。这不是空间不足,而是 session 的临时段上下文没刷新。

实操建议:

  • 查残留使用:SELECT tablespace_name, segfile#, segblk# FROM v$sort_usage;如果还显示旧表空间名,说明 session 没释放
  • 强制清理老 session 的临时段:ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE(加 IMMEDIATE 避免等待 rollback)
  • 应用侧需配合:连接池配置 idle timeout 和 validation query(如 SELECT 1 FROM DUAL),防止复用失效连接
  • 临时应急可设 ALTER SESSION SET TEMPORARY TABLESPACE temp_new,但不能替代全局切换

最易被忽略的是:OFFLINE DROP 后控制文件更新了,但 buffer cache 和 shared pool 里可能缓存着旧 tempfile 的字典信息,得靠 session 重建或 flush(不推荐 flush shared_pool)来清掉——所以优先杀 session 比等自动清理靠谱。

text=ZqhQzanResources