我们知道,我们如果把一些对象删除之后,如何回收表空间中的数据文件:
我们看如下的查询:
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
- 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;
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%,现在我们想回收这个表空间的数据,如何回收处理?
我们可以按照文件查询:
- 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;
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;
- 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
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>
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
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
这里显示:
SQL> alter database datafile '+DG_DATA8/oss139/datafile/lars01_index.464.798314649'resize 576M;
数据库已更改。
这个是单个文件的处理回收方法:
如果文件很多,我们可以直接这样查询:
- select
a.file#,a.name,a.bytes/1024/1024 Resize,(a.bytes-HWM*a.block_size)/1024/1024 ReleaseMB, - 'alter
database datafile '''||a.name||'''resize '||ceil(HWM*a.block_size/1024/1024+30)||'M;' ResizeCmd ---这里我习惯往前放大30M - from
v$datafile a, - (select
file_id,max(block_id+blocks-1) HWM from dba_extents - group
by file_id) b - where
a.file#=b.file_id(+) - 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
1. 创建表空间:
SQL> create tablespace daodao datafile '/u01/app/oracle/oradata/huangchao/daodao.dbf'
Tablespace created.
2. 创建一个表使用这个表空间:
create table daodao_1 tablespace daodao
3. 查询文件大小:
SQL> select BYTES/1024/1024,MAXBYTES/1024/1024 from Dba_Data_Files where tablespace_name ='DAODAO';
BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
现在文件还是在10M:
SQL> insert into
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
--------------- ------------------
SQL> select count(1) from
----------
下面的使用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)",
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;
1
从这里可以看出表空间只使用了20% ,我们做如下操作;
SQL> insert into 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)",
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;
1
这时候占用了56.77% ,我们如果这个时候要回收表空间的话,可以操作不?
回收数据文件操作:
SQL> select FILE_ID from dba_data_files where tablespace_name='DAODAO';
----------
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)",
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
1
这个时候再查询是可以看到表空间的回收目录:
--这个时候我们再查询数据文件: 使用了35M了
SQL> select BYTES/1024/1024,MAXBYTES/1024/1024 from Dba_Data_Files where tablespace_name ='DAODAO';
BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
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)",
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;
1
--可以看到用了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)",
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;
1
已经到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
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_2
DAODAO_1
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;