如何通过SQL脚本在执行INSERT前后自动检查表空间的剩余量?

老磊小哥_5635

老磊小哥_5635

2026-06-17

332人浏览

原创

dba_free_space 查询结果不准,因 oracle 按 extent 分配空间、lmt bitmap 延迟可见、未提交事务不更新该视图,且忽略最大连续空闲块大小;应结合 dba_extents 和 dba_segments 校验,并用 pl/sql 实现查-判-插-再查闭环。

如何通过sql脚本在执行insert前后自动检查表空间的剩余量?

INSERT 前后查 dba_free_space 为什么经常不准?

直接在 INSERT 前后执行 SELECT SUM(bytes) FROM dba_free_space 得到的“剩余空间”往往和实际可用值不一致,因为 Oracle 的段(segment)扩展不是按字节实时分配,而是按 extent 分配,且存在本地管理表空间(LMT)中 bitmap tracking 的延迟可见性。更关键的是:事务未提交时,新分配的 extent 不会立即反映在 dba_free_space 中,但已占用的空间却可能被其他会话抢占。

  • 必须用 dba_segments + dba_extents 双校验,而非只看 dba_free_space
  • 查询需加 AS OF TIMESTAMP 或在同事务内完成,否则快照不一致
  • 如果表空间是 AUTOALLOCATE 模式,首次 extent 大小可能是 64KB,后续可能跳到 1MB —— 不能假设均匀增长

用 PL/SQL 匿名块封装检查逻辑,避免手动重复

纯 SQL 脚本无法跨语句共享变量,也无法做条件跳过插入;必须用 PL/SQL 实现“查→判→插→再查”闭环。核心是把空间阈值、表名、插入语句都参数化,避免硬编码。

DECLARE
  v_free_bytes_before NUMBER;
  v_free_bytes_after  NUMBER;
  v_used_percent      NUMBER;
  v_threshold_pct     CONSTANT NUMBER := 85; -- 警戒水位
BEGIN
  SELECT ROUND((a.bytes - b.bytes) / a.bytes * 100, 2)
    INTO v_used_percent
    FROM (SELECT SUM(bytes) bytes FROM dba_data_files WHERE tablespace_name = 'USERS') a,
         (SELECT NVL(SUM(bytes), 0) bytes FROM dba_free_space WHERE tablespace_name = 'USERS') b;
<p>IF v_used_percent > v_threshold_pct THEN
RAISE_APPLICATION_ERROR(-20001, 'Tablespace USERS usage ' || v_used_percent || '% exceeds ' || v_threshold_pct || '%');
END IF;</p><p>SELECT NVL(SUM(bytes), 0) INTO v_free_bytes_before FROM dba_free_space WHERE tablespace_name = 'USERS';</p><p>INSERT INTO t1 VALUES (1, 'test'); -- 替换为你的真实 INSERT</p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/ai/1894" title="Postme"><img
														src="https://img.php.cn/upload/ai_manual/000/000/000/175680421960982.png" alt="Postme" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/ai/1894" title="Postme" class="overflowclass">Postme</a>
													<p class="overflowclass">一款面向外贸和跨境营销场景的AI写作工具,可辅助生成产品推广、营销沟通和海外市场所需的商业文案内容。</p>
												</div>
												<a rel="nofollow" href="/ai/1894" title="Postme" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div><p>SELECT NVL(SUM(bytes), 0) INTO v_free_bytes_after FROM dba_free_space WHERE tablespace_name = 'USERS';</p><p>DBMS_OUTPUT.PUT_LINE('Before: ' || v_free_bytes_before || ' bytes, After: ' || v_free_bytes_after || ' bytes');
END;
/</p>
  • dba_data_files 和 dba_free_space 必须同属一个表空间名,大小写敏感(尤其在非默认大写模式下)
  • 如果 INSERT 触发了 segment 扩展(如首次插入),v_free_bytes_after 可能比 v_free_bytes_before 小得多,甚至为 0 —— 这说明已无连续 extent 可用,即使 SUM(bytes) 看似还有余量
  • 务必在同一个会话中执行,否则 DBMS_OUTPUT 不会显示,且事务隔离会导致二次查询看到不同快照

替代方案:监控 dba_tablespace_usage_metrics 更稳定

Oracle 10g+ 提供动态性能视图 dba_tablespace_usage_metrics,它基于 AWR 快照聚合,刷新频率可控(默认每小时),数值比实时查询 dba_free_space 更平滑、更适合预警。但它不能用于 INSERT 前后的毫秒级判断,而是作为辅助验证。

  • 该视图中 used_space 单位是 blocks,不是 bytes,需乘以 block_size(查 dba_tablespaces)才可比对
  • 字段 tablespace_size 是最大允许大小(含 autoextend),而 used_space 是已分配段的总块数,不含 free space —— 所以它反映的是“已用”,不是“剩余”
  • 若你的表空间设置了 AUTOEXTEND ON,这个视图的 tablespace_size 会动态增长,但 dba_free_space 不会立刻体现新文件空间,容易误判

真正要防的不是“没空间”,而是“没连续 extent”

最常被忽略的一点:即使 dba_free_space 显示还有 500MB 剩余,但如果最大连续块(MAX(bytes))只有 64KB,而你要插入的数据触发了一个需要 1MB extent 的操作(比如 LOB 列或并行 DML),就会报 ORA-01652: unable to extend temp segment 或类似错误。

  • 务必加查:SELECT MAX(bytes) FROM dba_free_space WHERE tablespace_name = 'USERS'
  • 结合段类型判断:普通表插入一般用 INITIAL extent,但索引重建、CTAS、全局临时表等场景可能申请更大 extent
  • 如果业务允许,提前用 ALTER TABLESPACE ... COALESCE 合并相邻空闲区(仅限字典管理表空间);LMT 下只能依赖自动 bitmap 管理,此时更应关注 dba_extents 中相邻 extent 的物理连续性
实际部署时,别只盯着总数,连续性才是卡住 INSERT 的最后一根稻草。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3803

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

811

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

989

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5601

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2563

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5580

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7321

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

990

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

872

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.2万人学习