Skip to content

Oracle 空间不足故障

空间不足的症状

1. 错误信息

  • 表空间不足

    ORA-01653: unable to extend table OWNER.TABLE by 128 in tablespace TABLESPACE_NAME
  • 临时表空间不足

    ORA-01652: unable to extend temp segment by 128 in tablespace TEMP
  • UNDO 表空间不足

    ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS1'
  • 归档日志空间不足

    ORA-00257: archiver error. Connect internal only, until freed.

2. 数据库性能下降

  • 查询执行时间变长
  • 事务提交时间变长
  • 数据库响应变慢

3. 监控指标异常

  • 表空间使用率接近或达到 100%
  • 数据文件自动扩展频繁
  • 临时表空间使用率持续高位

空间不足的诊断方法

1. 检查表空间使用情况

  • 查看表空间使用率

    sql
    SELECT tablespace_name, 
           ROUND((total_space - free_space) / total_space * 100, 2) AS used_percent,
           total_space,
           free_space
    FROM (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS total_space
      FROM dba_data_files
      GROUP BY tablespace_name
    ) t1,
    (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS free_space
      FROM dba_free_space
      GROUP BY tablespace_name
    ) t2
    WHERE t1.tablespace_name = t2.tablespace_name
    ORDER BY used_percent DESC;
  • 查看临时表空间使用情况

    sql
    SELECT tablespace_name, 
           ROUND((total_space - free_space) / total_space * 100, 2) AS used_percent,
           total_space,
           free_space
    FROM (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS total_space
      FROM dba_temp_files
      GROUP BY tablespace_name
    ) t1,
    (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS free_space
      FROM dba_free_space
      WHERE tablespace_name IN (SELECT tablespace_name FROM dba_temp_files)
      GROUP BY tablespace_name
    ) t2
    WHERE t1.tablespace_name = t2.tablespace_name
    ORDER BY used_percent DESC;
  • 查看 UNDO 表空间使用情况

    sql
    SELECT tablespace_name, 
           ROUND((total_space - free_space) / total_space * 100, 2) AS used_percent,
           total_space,
           free_space
    FROM (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS total_space
      FROM dba_data_files
      WHERE tablespace_name IN (SELECT tablespace_name FROM dba_tablespaces WHERE contents = 'UNDO')
      GROUP BY tablespace_name
    ) t1,
    (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS free_space
      FROM dba_free_space
      WHERE tablespace_name IN (SELECT tablespace_name FROM dba_tablespaces WHERE contents = 'UNDO')
      GROUP BY tablespace_name
    ) t2
    WHERE t1.tablespace_name = t2.tablespace_name
    ORDER BY used_percent DESC;

2. 检查数据文件情况

  • 查看数据文件大小和自动扩展设置

    sql
    SELECT file_name, 
           tablespace_name,
           ROUND(bytes / 1024 / 1024, 2) AS size_mb,
           ROUND(maxbytes / 1024 / 1024, 2) AS max_size_mb,
           autoextensible
    FROM dba_data_files
    ORDER BY tablespace_name, file_name;
  • 查看数据文件增长历史

    sql
    SELECT file_name, 
           tablespace_name,
           increment_by * 8 / 1024 AS increment_mb
    FROM dba_data_files
    WHERE autoextensible = 'YES'
    ORDER BY tablespace_name, file_name;

3. 检查归档日志空间

  • 查看归档日志目标位置

    sql
    SHOW PARAMETER log_archive_dest;
  • 检查归档日志空间使用情况

    bash
    df -h <归档日志目>

4. 检查大对象和大表

  • 查看大表

    sql
    SELECT owner, 
           table_name,
           ROUND(bytes / 1024 / 1024, 2) AS size_mb
    FROM dba_segments
    WHERE segment_type = 'TABLE'
    ORDER BY bytes DESC
    FETCH FIRST 10 ROWS ONLY;
  • 查看大索引

    sql
    SELECT owner, 
           segment_name,
           ROUND(bytes / 1024 / 1024, 2) AS size_mb
    FROM dba_segments
    WHERE segment_type = 'INDEX'
    ORDER BY bytes DESC
    FETCH FIRST 10 ROWS ONLY;
  • 查看大分区

    sql
    SELECT owner, 
           segment_name,
           partition_name,
           ROUND(bytes / 1024 / 1024, 2) AS size_mb
    FROM dba_segments
    WHERE segment_type LIKE '%PARTITION'
    ORDER BY bytes DESC
    FETCH FIRST 10 ROWS ONLY;

空间不足的解决方案

1. 表空间不足的解决方案

方法 1:扩展数据文件

  • 手动扩展数据文件

    sql
    ALTER DATABASE DATAFILE '/u01/app/oracle/oradata/ORCL/users01.dbf' RESIZE 1000M;
  • 启用自动扩展

    sql
    ALTER DATABASE DATAFILE '/u01/app/oracle/oradata/ORCL/users01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法 2:添加数据文件

  • 添加数据文件
    sql
    ALTER TABLESPACE users ADD DATAFILE '/u01/app/oracle/oradata/ORCL/users02.dbf' SIZE 500M AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法 3:清理表空间

  • 删除不需要的表

    sql
    DROP TABLE owner.table_name;
  • 清理表数据

    sql
    DELETE FROM owner.table_name WHERE condition;
    COMMIT;
  • 重建表释放空间

    sql
    ALTER TABLE owner.table_name MOVE;
    ALTER INDEX owner.index_name REBUILD;
  • 使用分区表

    sql
    ALTER TABLE owner.table_name DROP PARTITION partition_name;

2. 临时表空间不足的解决方案

方法 1:扩展临时文件

  • 手动扩展临时文件

    sql
    ALTER DATABASE TEMPFILE '/u01/app/oracle/oradata/ORCL/temp01.dbf' RESIZE 1000M;
  • 启用自动扩展

    sql
    ALTER DATABASE TEMPFILE '/u01/app/oracle/oradata/ORCL/temp01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法 2:添加临时文件

  • 添加临时文件
    sql
    ALTER TABLESPACE temp ADD TEMPFILE '/u01/app/oracle/oradata/ORCL/temp02.dbf' SIZE 500M AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法 3:创建新的临时表空间

  • 创建新的临时表空间

    sql
    CREATE TEMPORARY TABLESPACE temp_new TEMPFILE '/u01/app/oracle/oradata/ORCL/temp_new01.dbf' SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;
  • 设置为默认临时表空间

    sql
    ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp_new;
  • 删除旧的临时表空间

    sql
    DROP TABLESPACE temp INCLUDING CONTENTS AND DATAFILES;

3. UNDO 表空间不足的解决方案

方法 1:扩展 UNDO 数据文件

  • 手动扩展 UNDO 数据文件

    sql
    ALTER DATABASE DATAFILE '/u01/app/oracle/oradata/ORCL/undotbs01.dbf' RESIZE 1000M;
  • 启用自动扩展

    sql
    ALTER DATABASE DATAFILE '/u01/app/oracle/oradata/ORCL/undotbs01.dbf' AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法 2:添加 UNDO 数据文件

  • 添加 UNDO 数据文件
    sql
    ALTER TABLESPACE undotbs1 ADD DATAFILE '/u01/app/oracle/oradata/ORCL/undotbs02.dbf' SIZE 500M AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;

方法 3:创建新的 UNDO 表空间

  • 创建新的 UNDO 表空间

    sql
    CREATE UNDO TABLESPACE undotbs2 DATAFILE '/u01/app/oracle/oradata/ORCL/undotbs201.dbf' SIZE 1000M AUTOEXTEND ON NEXT 100M MAXSIZE 2048M;
  • 切换到新的 UNDO 表空间

    sql
    ALTER SYSTEM SET undo_tablespace = 'undotbs2' SCOPE=BOTH;
  • 删除旧的 UNDO 表空间

    sql
    DROP TABLESPACE undotbs1 INCLUDING CONTENTS AND DATAFILES;

4. 归档日志空间不足的解决方案

方法 1:清理归档日志

  • 使用 RMAN 清理归档日志

    sql
    RMAN> DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-7';
  • 手动清理归档日志

    bash
    rm /archivelog/*.arc

方法 2:增加归档日志空间

  • 添加新的归档日志目标

    sql
    ALTER SYSTEM SET log_archive_dest_2 = 'LOCATION=/new_archivelog' SCOPE=BOTH;
  • 扩展归档日志所在的文件系统

    • 使用 LVM 扩展文件系统
    • 添加新的磁盘并挂载到归档日志目录

方法 3:调整归档日志保留策略

  • 设置归档日志保留策略

    sql
    CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;
  • 启用归档日志自动删除

    sql
    CONFIGURE ARCHIVELOG DELETION POLICY TO BACKED UP 1 TIMES TO 'DISK';

空间不足的预防措施

1. 监控空间使用情况

  • 使用 Oracle Enterprise Manager:设置空间使用告警

  • 使用自动监控脚本

    sql
    -- 检查表空间使用率
    SELECT tablespace_name, 
           ROUND((total_space - free_space) / total_space * 100, 2) AS used_percent
    FROM (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS total_space
      FROM dba_data_files
      GROUP BY tablespace_name
    ) t1,
    (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS free_space
      FROM dba_free_space
      GROUP BY tablespace_name
    ) t2
    WHERE t1.tablespace_name = t2.tablespace_name
    AND (total_space - free_space) / total_space * 100 > 80;

2. 合理规划表空间

  • 初始大小:设置合理的初始大小
  • 自动扩展:启用自动扩展,但设置最大大小
  • 多个数据文件:为大型表空间创建多个数据文件
  • 数据文件分布:将数据文件分布在不同的磁盘上

3. 数据管理策略

  • 分区表:使用分区表管理大型表
  • 表压缩:启用表压缩减少存储空间
  • 定期清理:定期清理不需要的数据
  • 归档策略:建立数据归档策略

4. 空间使用审计

  • 定期审计:定期审计表空间使用情况
  • 识别增长趋势:分析数据增长趋势
  • 预测空间需求:根据增长趋势预测未来空间需求
  • 调整策略:根据审计结果调整空间管理策略

常见问题(FAQ)

Q1: 如何快速识别空间不足的表空间?

A1: 快速识别空间不足的表空间的方法:

  • 使用 SQL 查询

    sql
    SELECT tablespace_name, 
           ROUND((total_space - free_space) / total_space * 100, 2) AS used_percent
    FROM (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS total_space
      FROM dba_data_files
      GROUP BY tablespace_name
    ) t1,
    (
      SELECT tablespace_name,
             SUM(bytes) / 1024 / 1024 AS free_space
      FROM dba_free_space
      GROUP BY tablespace_name
    ) t2
    WHERE t1.tablespace_name = t2.tablespace_name
    ORDER BY used_percent DESC
    FETCH FIRST 5 ROWS ONLY;
  • 使用 Oracle Enterprise Manager:查看表空间使用率仪表盘

Q2: 如何防止临时表空间不足?

A2: 防止临时表空间不足的方法:

  • 合理设置临时表空间大小:根据查询需求设置合适的大小
  • 多个临时文件:创建多个临时文件,分布在不同的磁盘上
  • 监控临时表空间使用:设置临时表空间使用率告警
  • 优化查询:减少需要大量临时空间的查询
  • 使用适当的排序参数:调整 PGA 大小,减少临时表空间使用

Q3: 如何处理大量小表占用表空间的情况?

A3: 处理大量小表占用表空间的情况的方法:

  • 使用分区表:将相关的小表合并为分区表
  • 表压缩:启用表压缩减少存储空间
  • 定期清理:清理不需要的小表
  • 使用本地管理表空间:使用本地管理表空间减少字典管理开销
  • 调整区大小:为小表设置合适的区大小

Q4: 如何预测未来的空间需求?

A4: 预测未来空间需求的方法:

  • 分析历史增长趋势

    sql
    -- 分析表空间增长趋势
    SELECT tablespace_name, 
           AVG(growth_mb) AS avg_growth_mb_per_day
    FROM (
      SELECT tablespace_name,
             (current_bytes - previous_bytes) / 1024 / 1024 AS growth_mb
      FROM (
        SELECT tablespace_name,
               SUM(bytes) AS current_bytes,
               LAG(SUM(bytes)) OVER (PARTITION BY tablespace_name ORDER BY snap_id) AS previous_bytes
        FROM dba_hist_tbspc_space_usage
        GROUP BY tablespace_name, snap_id
      )
      WHERE previous_bytes IS NOT NULL
    )
    GROUP BY tablespace_name;
  • 使用 AWR 报告:分析表空间增长历史

  • 建立预测模型:基于历史数据建立空间增长预测模型

Q5: 如何处理 LOB 段占用大量空间的情况?

A5: 处理 LOB 段占用大量空间的情况的方法:

  • 使用 LOB 压缩

    sql
    ALTER TABLE owner.table_name MODIFY LOB (lob_column) (COMPRESS);
  • 重建 LOB 段

    sql
    ALTER TABLE owner.table_name MOVE LOB (lob_column) STORE AS (TABLESPACE lob_tablespace);
  • 清理不需要的 LOB 数据

    sql
    DELETE FROM owner.table_name WHERE lob_column IS NULL;
    COMMIT;
  • 使用 SecureFiles:对于 Oracle 11g 及以上版本,使用 SecureFiles 存储 LOB 数据

Q6: 如何在不影响数据库运行的情况下清理表空间?

A6: 在不影响数据库运行的情况下清理表空间的方法:

  • 使用分区表:删除旧的分区

  • 在线重建表

    sql
    ALTER TABLE owner.table_name MOVE ONLINE;
  • 使用 DBMS_REDEFINITION:在线重定义表

  • 分批清理:分批删除数据,避免长时间锁定

  • 低峰期操作:在数据库低峰期进行清理操作