【转】如何收缩表空间中的数据文件…

我们知道,我们如果把一些对象删除之后,如何回收表空间中的数据文件:

我们看如下的查询:

create or replace view dba_tablespace_free as
select a.tablespace_name,a.total_space_mb allocated_space_mb,round(b.free_space_mb,2) free_space_mb,(a.max_space-a.total_space_mb) free_allocate_mb,round(a.max_space,2) max_space_mb,
round((a.total_space_mb-b.free_space_mb)/a.total_space_mb*100,2) pct_usage,round(a.total_space_mb/a.max_space*100,2) pct_allocated
from (select tablespace_name,sum(bytes)/1024/1024 total_space_Mb,decode(sum(maxbytes/1024/1024),0,
sum(bytes)/1024/1024,sum(case when then maxbytes
                             else bytes end)/1024/1024) max_space
 from dba_data_files  group by tablespace_name)a,(select tablespace_name, sum((bytes)/1024/1024) free_space_Mb
 from dba_free_space group by tablespace_name) b where a.tablespace_name=b.tablespace_name;

[sql]
  1. SELECT UPPER(F.TABLESPACE_NAME) "表空间名",  
  2.   D.TOT_GROOTTE_MB "表空间大小(M)",  
  3.   D.TOT_GROOTTE_MB F.TOTAL_BYTES "已使用空间(M)",  
  4.   TO_CHAR(ROUND((D.TOT_GROOTTE_MB F.TOTAL_BYTES) D.TOT_GROOTTE_MB 100,2),'990.99') || '%' "使用比",  
  5.   F.TOTAL_BYTES "已扩展空闲空间(M)",  
  6.     (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free where a.tablespace_name= f.tablespace_name) "总剩余空间",  
  7.   F.MAX_BYTES "最大块(M)"  
  8.   FROM (SELECT TABLESPACE_NAME,  
  9.   ROUND(SUM(BYTES) (1024 1024), 2) TOTAL_BYTES,  
  10.   ROUND(MAX(BYTES) (1024 1024), 2) MAX_BYTES  
  11.   FROM SYS.DBA_FREE_SPACE  
  12.   GROUP BY TABLESPACE_NAME) F,  
  13.   (SELECT DD.TABLESPACE_NAME,  
  14.   ROUND(SUM(DD.BYTES) (1024 1024), 2) TOT_GROOTTE_MB  
  15.   FROM SYS.DBA_DATA_FILES DD  
  16.   GROUP BY DD.TABLESPACE_NAME)  
  17.   WHERE D.TABLESPACE_NAME F.TABLESPACE_NAME  
  18.   ORDER BY desc;  
SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
  D.TOT_GROOTTE_MB "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
  F.TOTAL_BYTES "已扩展空闲空间(M)",
    (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free a where a.tablespace_name= f.tablespace_name) "总剩余空间",
  F.MAX_BYTES "最大块(M)"
  FROM (SELECT TABLESPACE_NAME,
  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
  FROM SYS.DBA_FREE_SPACE
  GROUP BY TABLESPACE_NAME) F,
  (SELECT DD.TABLESPACE_NAME,
  ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
  FROM SYS.DBA_DATA_FILES DD
  GROUP BY DD.TABLESPACE_NAME) D
  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
  ORDER BY 3 desc;


查询结果:

其中一个表空间lars01_index分配了3T,但是只用了8%,现在我们想回收这个表空间的数据,如何回收处理?

我们可以按照文件查询:

[sql]
  1. select tablespace_name,  
  2.        file_name,  
  3.        a.file_id,  
  4.        bytes 1024 1024 file_size,  
  5.        round(a.free_size, 2) free_size,  
  6.        autoextensible,  
  7.        increment_by next,  
  8.        round(maxbytes 1024 1024 1024) max_size,  
  9.        round(((bytes 1024 1024) a.free_size) (bytes 1024 1024) 100,  
  10.              2) used_rate  
  11.   from dba_data_files b,  
  12.        (select file_id, sum(bytes) 1024 1024 free_size  
  13.           from dba_free_space  
  14.          group by file_id)  
  15.  where b.file_id a.file_id  
  16.  and tablespace_name ='LARS01_INDEX'  
  17.  order by used_rate desc;  
select tablespace_name,
       file_name,
       a.file_id,
       bytes / 1024 / 1024 file_size,
       round(a.free_size, 2) free_size,
       autoextensible,
       increment_by next,
       round(maxbytes / 1024 / 1024 / 1024) max_size,
       round(((bytes / 1024 / 1024) - a.free_size) / (bytes / 1024 / 1024) * 100,
             2) used_rate
  from dba_data_files b,
       (select file_id, sum(bytes) / 1024 / 1024 free_size
          from dba_free_space
         group by file_id) a
 where b.file_id = a.file_id
 and tablespace_name ='LARS01_INDEX'
 order by used_rate desc;


 我们针对第一个文件435:

[sql]
  1. SQL> select max(block_id) from dba_extents where file_id=435 and tablespace_name='LARS01_INDEX';  
  2.   
  3. MAX(BLOCK_ID)  
  4. -------------  
  5.       4177033  
  6.   
  7. SQL> select 4177033*8/1024 from dual;  
  8.   
  9. 4177033*8/1024  
  10. --------------  
  11.     32633.0703  
SQL> select max(block_id) from dba_extents where file_id=435 and tablespace_name='LARS01_INDEX';

MAX(BLOCK_ID)
-------------
      4177033

SQL> select 4177033*8/1024 from dual;

4177033*8/1024
--------------
    32633.0703


这里最大块是在32G的位置,从这里看到尽快使用率是1%,也就是使用了320M,但是由于这个文件的位置,所以我们要回收的话,是无法直接resize的。

我们查看下文件高水位的分布,按照block_id进行排序:


从这里可以看出有不少对象是在比较高的地方:

把这些对象移动到新的表空间里面:

移除完比较大的block_id之后再次查询:

[sql]
  1. SQL> select max(block_id)*8/1024 from dba_extents where file_id=435 and tablespace_name='LARS01_INDEX';  
  2.   
  3. MAX(BLOCK_ID)*8/1024  
  4. --------------------  
  5.           537.070313  
SQL> select max(block_id)*8/1024 from dba_extents where file_id=435 and tablespace_name='LARS01_INDEX';

MAX(BLOCK_ID)*8/1024
--------------------
          537.070313

这里显示:  最大的block_id为537M,也就是这个是可以回收的文件的高水位:

SQL> alter database datafile '+DG_DATA8/oss139/datafile/lars01_index.464.798314649'resize 576M;

数据库已更改。

这个是单个文件的处理回收方法:

如果文件很多,我们可以直接这样查询:

[sql]
  1. select a.file#,a.name,a.bytes/1024/1024 Resize,(a.bytes-HWM*a.block_size)/1024/1024 ReleaseMB,  
  2. 'alter database datafile '''||a.name||'''resize '||ceil(HWM*a.block_size/1024/1024+30)||'M;' ResizeCmd   ---这里我习惯往前放大30M  
  3. from v$datafile a,  
  4. (select file_id,max(block_id+blocks-1) HWM from dba_extents  
  5. group by file_id)  
  6. where a.file#=b.file_id(+)  
  7. and (a.bytes-HWM*a.block_size)/1024/1024>100;    ---空闲多余100M以上才回收。  

 

 

实验脚本:

create or replace view dba_tablespace_free as
select a.tablespace_name,a.total_space_mb allocated_space_mb,round(b.free_space_mb,2) free_space_mb,(a.max_space-a.total_space_mb) free_allocate_mb,round(a.max_space,2) max_space_mb,
round((a.total_space_mb-b.free_space_mb)/a.total_space_mb*100,2) pct_usage,round(a.total_space_mb/a.max_space*100,2) pct_allocated
from (select tablespace_name,sum(bytes)/1024/1024 total_space_Mb,decode(sum(maxbytes/1024/1024),0,
sum(bytes)/1024/1024,sum(case when then maxbytes
                             else bytes end)/1024/1024) max_space
 from dba_data_files  group by tablespace_name)a,(select tablespace_name, sum((bytes)/1024/1024) free_space_Mb
 from dba_free_space group by tablespace_name) b where a.tablespace_name=b.tablespace_name;

 

1. 创建表空间:
SQL> create tablespace daodao datafile '/u01/app/oracle/oradata/huangchao/daodao.dbf'  size 10M autoextend on next 50M;
Tablespace created.
2. 创建一个表使用这个表空间:
create table daodao_1 tablespace daodao  as select * from dba_objects ;
3. 查询文件大小:

SQL> select BYTES/1024/1024,MAXBYTES/1024/1024 from Dba_Data_Files where tablespace_name ='DAODAO';

BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
             10         32767.9844

现在文件还是在10M:
SQL> insert into   daodao_1   select * from dba_objects ;

50748 rows created.

SQL> commit;

Commit complete.

SQL> select BYTES/1024/1024,MAXBYTES/1024/1024 from Dba_Data_Files where tablespace_name ='DAODAO';

BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
             60         32767.9844   ---这里60是由于表空间下个扩展占用了50M:

SQL> select count(1) from  daodao_1;

  COUNT(1)
----------
    101496

下面的使用plsql dev查询:
SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
  D.TOT_GROOTTE_MB "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
  F.TOTAL_BYTES "当前空闲空间(M)",
    (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free a where a.tablespace_name= f.tablespace_name) "总剩余空间",
  F.MAX_BYTES "最大块(M)"
  FROM (SELECT TABLESPACE_NAME,
  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
  FROM SYS.DBA_FREE_SPACE
  GROUP BY TABLESPACE_NAME) F,
  (SELECT DD.TABLESPACE_NAME,
  ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
  FROM SYS.DBA_DATA_FILES DD
  GROUP BY DD.TABLESPACE_NAME) D
  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
and f.tablespace_name='DAODAO'
  ORDER BY 3 desc;

DAODAO 60 12.06   20.10% 47.94 32755.924375 47.94

从这里可以看出表空间只使用了20% ,我们做如下操作;
SQL> insert into daodao_1   select * from daodao_1 ;

152245 rows created.

SQL> commit;

Commit complete.

 

现在再查看剩余表空间:
SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
  D.TOT_GROOTTE_MB "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
  F.TOTAL_BYTES "当前空闲空间(M)",
    (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free a where a.tablespace_name= f.tablespace_name) "总剩余空间",
  F.MAX_BYTES "最大块(M)"
  FROM (SELECT TABLESPACE_NAME,
  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
  FROM SYS.DBA_FREE_SPACE
  GROUP BY TABLESPACE_NAME) F,
  (SELECT DD.TABLESPACE_NAME,
  ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
  FROM SYS.DBA_DATA_FILES DD
  GROUP BY DD.TABLESPACE_NAME) D
  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
and f.tablespace_name='DAODAO'
  ORDER BY 3 desc;

DAODAO 60 34.06   56.77% 25.94 32733.924375 25.94

这时候占用了56.77% ,我们如果这个时候要回收表空间的话,可以操作不?

回收数据文件操作:

SQL> select FILE_ID from dba_data_files where tablespace_name='DAODAO';

   FILE_ID
----------
         8

SQL> alter database datafile 8 resize 35M;

Database altered.

SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
  D.TOT_GROOTTE_MB "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
  F.TOTAL_BYTES "当前空闲空间(M)",
    (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free a where a.tablespace_name= f.tablespace_name) "总剩余空间",
  F.MAX_BYTES "最大块(M)"
  FROM (SELECT TABLESPACE_NAME,
  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
  FROM SYS.DBA_FREE_SPACE
  GROUP BY TABLESPACE_NAME) F,
  (SELECT DD.TABLESPACE_NAME,
  ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
  FROM SYS.DBA_DATA_FILES DD
  GROUP BY DD.TABLESPACE_NAME) D
  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
and f.tablespace_name='DAODAO'
  ORDER BY 3

DAODAO 35 34.06   97.31% 0.94 32733.924375 0.94
这个时候再查询是可以看到表空间的回收目录:

--这个时候我们再查询数据文件: 使用了35M了

SQL> select BYTES/1024/1024,MAXBYTES/1024/1024 from Dba_Data_Files where tablespace_name ='DAODAO';

BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
             35         32767.9844

SQL> create table daodao_2 tablespace daodao as select * from dba_objects;

Table created.

查看剩余表空间:

SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
  D.TOT_GROOTTE_MB "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
  F.TOTAL_BYTES "当前空闲空间(M)",
    (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free a where a.tablespace_name= f.tablespace_name) "总剩余空间",
  F.MAX_BYTES "最大块(M)"
  FROM (SELECT TABLESPACE_NAME,
  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
  FROM SYS.DBA_FREE_SPACE
  GROUP BY TABLESPACE_NAME) F,
  (SELECT DD.TABLESPACE_NAME,
  ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
  FROM SYS.DBA_DATA_FILES DD
  GROUP BY DD.TABLESPACE_NAME) D
  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
and f.tablespace_name='DAODAO'
  ORDER BY 3 desc;

DAODAO 85 40.06   47.13% 44.94 32727.924375 44.94

--可以看到用了40M了


SQL> truncate table daodao_1;

Table truncated.

这个时候查看表空间剩余:

SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
  D.TOT_GROOTTE_MB "表空间大小(M)",
  D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
  TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
  F.TOTAL_BYTES "当前空闲空间(M)",
    (SELECT free_space_mb+free_allocate_mb FROM dba_tablespace_free a where a.tablespace_name= f.tablespace_name) "总剩余空间",
  F.MAX_BYTES "最大块(M)"
  FROM (SELECT TABLESPACE_NAME,
  ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
  ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES
  FROM SYS.DBA_FREE_SPACE
  GROUP BY TABLESPACE_NAME) F,
  (SELECT DD.TABLESPACE_NAME,
  ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB
  FROM SYS.DBA_DATA_FILES DD
  GROUP BY DD.TABLESPACE_NAME) D
  WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
and f.tablespace_name='DAODAO'
  ORDER BY 3 desc;

DAODAO 85 6.12    7.20% 78.88 32761.864375 44.94


已经到6M了,那我们可以回收到7M不?
执行如下:
SQL> alter database datafile 8 resize 7M;
alter database datafile 8 resize 7M
*
ERROR at line 1:
ORA-03297: file contains used data beyond requested RESIZE value

报错了,知道为什么了吗?

select  segment_name,block_id,blocks FROM dba_extents where Tablespace_name ='DAODAO' order by block_id desc;

DAODAO_2 5001 128
DAODAO_2 4873 128
DAODAO_2 4745 128
DAODAO_2 4617 128
DAODAO_2 4489 128
DAODAO_2 4481 8
DAODAO_2 4473 8
DAODAO_2 4465 8
DAODAO_2 4457 8
DAODAO_2 4449 8
DAODAO_2 4441 8
DAODAO_2 4433 8
DAODAO_2 4425 8
DAODAO_2 4417 8
DAODAO_2 4409 8
DAODAO_2 4401 8
DAODAO_2 4393 8
DAODAO_2 4385 8
DAODAO_2 4377 8
DAODAO_2 4369 8
DAODAO_2 4361 8
DAODAO_1 8

daodao_2占用的空间等于5001-4361+128=768

select segment_name from dba_segments where segment_name ='DAODAO_2';

select SEGMENT_NAME,BLOCKS from dba_segments where segment_name ='DAODAO_2';

 

alter table daodao_2 move;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

科技改变未来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值