一次意外的 ORA-01652
C系统是一个业务繁忙的批量作业系统,每天加工超过300GB的数据,是一个数据量大、加工时效要求高的系统。为提高效率,应用大量使用"CTAS+分区交换"替代大事务的"DELETE+INSERT"操作进行数据归档。
某日日终跑批时,在表空间TBS(剩余空间约2.7TB)上新建表T1(约1GB)时,出现“表空间不足”的错误。报错信息如下:
ORA-01652 文档解释是: Failed to allocate an extent of the required number of blocks for a temporary segment in the tablespace indicated。
为什么说意外
1、系统每天监控表空间使用量,始终保持使用率在80%以内。表空间TBS剩余2.7TB,总空间13TB。
2、通过CTAS(Create Table As Select)新建的T1表,记录数为七百多万,数据大小约为1G。
以上似乎说明:存储空间容量看起来没问题。
继续验证分析
经过反复检查验证,发现:当给select 语句加上只取40万条记录的限制,可成功创建N张T2(58MB)表;但是当把记录数限制放大到50万(72MB)的时候,就出现ORA-01652错误。
为什么2.7G的可用空间却建不了1GB的表?
为什么建n张58MB的表可以,一张72MB的表就不行呢?
以下我们根据ORACLE数据库的表空间管理方式,并进行验证来解析这个问题。
表空间的管理方式
图1 oracle 数据的存储结构
如图1所示:Oracle存储层级:TABLESPACE>SEGMENT(TABLE/INDEX/PARTITION)->EXTENT->BLOCKS。
在ORACLE数据库中,表空间中的空闲空间是以extent的形式组织的,分配空间时也是按照extent分配的。extent存在两种管理方式:SYSTEM、UNIFORM,需要在创建表空间时指定。
当新建一张表(或者一个分区)时,系统就为该表空间分配一个初始EXTENT,并按需不断新增EXTENT。新EXTENT的大小根据表空间的管理方式确定,如下图:
系统剩余空间分析
本例中,由于TBS表空间管理方式为 SYSTEM,通过dba_free_space 对TBS剩余空间分布进行分析:
发现剩余表空间的EXTENT分布如下:
问题定位
根据以上分析,由于表空间碎片化严重,剩余的2.7TB空间中,已经没有大于8M的EXTENT,所以出现 ORA-01652错误。这就解释了上面我们提出的两个问题:
1)为什么2.7G的可用空间却建不了1GB的表?(缺少>=8MB的EXTENT)
2)为什么建n张58MB的表可以(<=1MB的EXTENT充足),一张72MB的表就不行呢?(缺少>=8MB的EXTENT)
解决方案
临时应急方案:
拓展表空间或者清理部分数据,增加大于8M/64M的空闲EXTENT数量。
解决方案:
将表空间管理方式由SYSTEM改为UNIFORM。
实施步骤:
1)申请13T临时存储空间进行过渡。
2)新建表空间TBS3,新表空间采用uniform size空间管理方式,size设置为2M
3)逐渐将TBS中的数据表挪到TBS3(alter table xxxx move tablespace TBS3),需要注意的是:对于包含long或LOB类型的表,无法通过alter table move的方式进行移动,得通过数据泵导入导出。
4)调整完成后,删除TBS表空间,释放存储空间并归还。
拓展阅读--行内表空间碎片化的监控
目前行内对于ORACLE数据库表空间碎片化触发告警需要同时满足以下条件:
1、可用EXTENT(<32MB) / 全部可用表空间 > 40%;
2、可用EXTENT(>32MB)总计小于20GB;
在本例中,由于系统每日空间需求较大,可用EXTENT(>32MB)为20GB时,无法满足一个跑批日的空间需求,因此对于这类应用,需要适当调整监控阈值。
拓展思考
在使用EXTENT管理使用SYSTEM方式时:
1、当sql执行时加入parallel的hint后,是否会加快碎片化速度?
2、当使用alter table move ...... compress ...... 后,是否可以减少表空间的碎片化?