今天突然发现一个表空间的空间不足,后台开始报错:ORA-1653。
奇怪的是,上周才检查过表空间的容量,这个表空间还有20G左右的空间,怎么这么快就用完了。
检查了是哪个表占用了大量的空间:
SQL> SELECT * FROM
2 (
3 SELECT SEGMENT_NAME, SUM(BYTES)/1024/1024/1024 G
4 FROM DBA_SEGMENTS
5 WHERE OWNER = 'ZHEJIANG'
6 GROUP BY SEGMENT_NAME
7 ORDER BY 2 DESC
8 )
9 WHERE ROWNUM < 5;
SEGMENT_NAME G
-------------------------------- ----------
ORD_ORDER_RECEIVE 21.3242188
ORD_HIT_COMM 5.47070313
CAT_LOG_AREA_PRICE 5.0625
ORD_ORDER_ITEM 3.19335938
问题对象已经找到,这个表的空间占用了21g,而正常情况下,这个表应该不会超过3个G。
检查表的数据量是否发生数据量级的增长:
SQL> SELECT COUNT(*) FROM ZHEJIANG.ORD_ORDER_RECEIVE;
COUNT(*)
----------
4141294
总共四百万条记录,这个数据量也很正常,再看看表的记录长度:
SQL> SELECT AVG_ROW_LEN FROM DBA_TABLES
2 WHERE TABLE_NAME = 'ORD_ORDER_RECEIVE'
3 AND OWNER = 'ZHEJIANG';
AVG_ROW_LEN
-----------
323
这个平均长度也没有问题,如果根据表的大小除以表记录数计算来计算平均长度:
SQL> select 21.3242188*1024*1024*1024/4136937 from dual;
21.3242188*1024*1024*1024/4136937
---------------------------------
5534.70009
这个长度就离谱了,计算这个表的最大长度:
SQL> SELECT SUM(DATA_LENGTH) FROM DBA_TAB_COLUMNS
2 WHERE OWNER = 'ZHEJIANG'
3 AND TABLE_NAME = 'ORD_ORDER_RECEIVE';
SUM(DATA_LENGTH)
----------------
777
最大长度才777,可是现在这张表的平均大小已经到了5K多,看来表中存在大量没有使用的BLOCK。
SQL> SELECT INDEX_NAME,
2 SUM(S.BYTES)/1024/1024 M
3 FROM DBA_INDEXES I, DBA_SEGMENTS S
4 WHERE I.OWNER = 'ZHEJIANG'
5 AND S.OWNER = 'ZHEJIANG'
6 AND SEGMENT_TYPE = 'INDEX'
7 AND SEGMENT_NAME = INDEX_NAME
8 AND TABLE_NAME = 'ORD_ORDER_RECEIVE'
9 GROUP BY INDEX_NAME;
INDEX_NAME M
www.ixdba.net
------------------------------ ----------
TU_ORD_ORDER_COMB_ITEM_FLAG 224
TU_ORD_ORDER_RECEIVE_PROD_ID 204
IND_ORD_ORDER_REC_REC_DATE 108
PK_ORD_ORDER_RECEIVE 196
IND_ORD_RECEIVE_BUYERSENDER 340
索引的大小都很正常,看来问题只是出在了表上,下面通过两个DBMS_SPACE来检查表的block使用情况,这里对两个过程进行了简单的封装:
SQL> create or replace procedure p_unused_space(p_object_name in varchar2,
2 p_object_type in varchar2 default 'TABLE',
3 p_owner in varchar2 default user,
4 p_partition_name in varchar2 default '') is
5 v_total_blocks number;
6 v_total_bytes number;
7 v_unused_blocks number;
8 v_unused_bytes number;
9 v_last_used_extent_file_id number;
10 v_last_used_extent_block_id number;
11 v_last_used_block number;
12 begin
13 dbms_space.unused_space(upper(p_owner), upper(p_object_name), upper(p_object_type), v_total_blocks,
14 v_total_bytes, v_unused_blocks, v_unused_bytes, v_last_used_extent_file_id,
15 v_last_used_extent_block_id, v_last_used_block, upper(p_partition_name));