本文介绍Oracle收缩数据文件的相关操作,运维工作中有时会需要通过收缩数据文件来释放磁盘空间。
数据文件初始化方式:
1.我们创建表空间一般有两种方式初始化其数据文件,即指定初始大小为32G(很大的值)或指定初始大小为100M(很小的值)然后通过自动扩展方式慢慢按需增长。
2.第一种初始数据文件方法坏处就是开始不管你用不用到那么大,都会占用这么大的磁盘空间(这种数据迁移的时候可以使用)。第二种初始化方法按需增长,比较好的监控实际使用磁盘空间,所以推荐初始值很小,使用自动扩展慢慢增长的方式。
一、查看表空间使用情况
1.查询除temp外表空间使用情况
SELECT a.tablespace_name "tb_name",
total / (1024 * 1024 * 1024) "tb_sizeG)",
free / (1024 * 1024 * 1024) "tb_free_size(G)",
(total - free) / (1024 * 1024 * 1024) "tb_used_size(G)",
round((total - free) / total, 4) * 100 "tb_usage %"
FROM (SELECT tablespace_name, SUM(bytes) free
FROM dba_free_space
GROUP BY tablespace_name) a,
(SELECT tablespace_name, SUM(bytes) total
FROM dba_data_files
GROUP BY tablespace_name) b
WHERE a.tablespace_name = b.tablespace_name;
或
select a.tablespace_name tnm,b.FILE_PATH,--b.autoextensible,
b.cnt,
trunc(a.bytes/1024/1024/1024) total_G,
trunc(a.bytes/1024/1024/1024/b.cnt) avg_G,
trunc(c.bytes/1024/1024/1024) free_G,
trunc((a.bytes-c.bytes)*100/a.bytes,2) used--,(c.bytes*100)/a.bytes "% FREE"
from SYS.SM$TS_AVAIL A,SYS.SM$TS_FREE C,
(select tablespace_name,substr(file_name,1,instr(file_name,'/',2)) FILE_PATH, --f.autoextensible,
count(*) cnt
from dba_data_files f group by
tablespace_name,substr(file_name,1,instr(file_name,'/',2))--,autoextensible
) b
WHERE A.TABLESPACE_NAME=C.TABLESPACE_NAME(+)
AND A.TABLESPACE_NAME=B.TABLESPACE_NAME
-- AND A.TABLESPACE_NAME IN (select distinct tablespace_name from dba_tablespaces)
order by avg_g desc;
2.查询包含temp在内的所有表空间使用情况
SELECT *
FROM (SELECT a.tablespace_name,
to_char(a.bytes / 1024 / 1024, '999,999,999') || 'M' total_bytes,
to_char(b.bytes / 1024 / 1024, '999,999,999') || 'M' free_bytes,
to_char(a.bytes / 1024 / 1024 - b.bytes / 1024 / 1024,
'999,999,999') || 'M' use_bytes,
to_char((1 - b.bytes / a.bytes) * 100, '990.99') || '%' USE
FROM (SELECT tablespace_name, sum(bytes) bytes
FROM dba_data_files
GROUP BY tablespace_name) a,
(SELECT tablespace_name, sum(bytes) bytes
FROM dba_free_space
GROUP BY tablespace_name) b
WHERE a.tablespace_name = b.tablespace_name
UNION ALL
SELECT c.tablespace_name,
to_char(c.bytes / 1024 / 1024, '999,999,999') || 'M' total_bytes,
to_char((c.bytes - d.bytes_used) / 1024 / 1024, '999,999,999') || 'M' free_bytes,
to_char(d.bytes_used / 1024 / 1024, '999,999,999') || 'M' use_bytes,
to_char(d.bytes_used * 100 / c.bytes, '990.99') || '%' USE
FROM (SELECT tablespace_name, sum(bytes) bytes
FROM dba_temp_files
GROUP BY tablespace_name) c,
(SELECT tablespace_name, sum(bytes_cached) bytes_used
FROM v$temp_extent_pool
GROUP BY tablespace_name) d
WHERE c.tablespace_name = d.tablespace_name);
或
select d.tablespace_name,
decode(d.status, 'ONLINE', 'OLN', 'READ ONLY', 'R/O', d.status) status,
d.extent_management,
decode(d.allocation_type, 'USER', '', d.allocation_type) allocation_type,
(case
when initial_extent < 1048576 then
lpad(round(initial_extent / 1024, 0), 3) || 'K'
else
lpad(round(initial_extent / 1024 / 1024, 0), 3) || 'M'
end) Ext_Size,
NVL(a.bytes / 1024 / 1024, 0) MB,
NVL(f.bytes / 1024 / 1024, 0) free,
(NVL(a.bytes / 1024 / 1024, 0) - NVL(f.bytes / 1024 / 1024, 0)) used,
NVL(l.large / 1024 / 1024, 0) largest,
d.MAX_EXTENTS,
lpad(round((f.bytes / a.bytes) * 100, 0), 3) pfree,
(case
when round(f.bytes / a.bytes * 100, 0) >= 20 then
' '
else
'*'
end) alrt
FROM sys.dba_tablespaces d,
(SELECT tablespace_name, SUM(bytes) bytes
FROM dba_data_files
GROUP BY tablespace_name) a,
(SELECT tablespace_name, SUM(bytes) bytes
FROM dba_free_space
GROUP BY tablespace_name) f,
(SELECT tablespace_name, MAX(bytes) large
FROM dba_free_space
GROUP BY tablespace_name) l
WHERE d.tablespace_name = a.tablespace_name(+)
AND d.tablespace_name = f.tablespace_name(+)
AND d.tablespace_name = l.tablespace_name(+)
AND NOT
(d.extent_management LIKE 'LOCAL' AND d.contents LIKE 'TEMPORARY')
UNION ALL
select d.tablespace_name,
decode(d.status, 'ONLINE', 'OLN', 'READ ONLY', 'R/O', d.status) status,
d.extent_management,
decode(d.allocation_type,
'UNIFORM',
'U',
'SYSTEM',
'A',
'USER',
'',
d.allocation_type) allocation_type,
(case
when initial_extent < 1048576 then
lpad(round(initial_extent / 1024, 0), 3) || 'K'
else
lpad(round(initial_extent / 1024 / 1024, 0), 3) || 'M'
end) Ext_Size,
NVL(a.bytes / 1024 / 1024, 0) MB,
(NVL(a.bytes / 1024 / 1024, 0) - NVL(t.bytes / 1024 / 1024, 0)) free,
NVL(t.bytes / 1024 / 1024, 0) used,
NVL(l.large / 1024 / 1024, 0) largest,
d.MAX_EXTENTS,
lpad(round(nvl(((a.bytes - t.bytes) / NVL(a.bytes, 0)) * 100, 100),
0),
3) pfree,
(case
when nvl(round(((a.bytes - t.bytes) / NVL(a.bytes, 0)) * 100, 0),
100) >= 20 then
' '
else
'*'
end) alrt
FROM sys.dba_tablespaces d,
(SELECT tablespace_name, SUM(bytes) bytes
FROM dba_temp_files
GROUP BY tablespace_name
order by tablespace_name) a,
(SELECT tablespace_name, SUM(bytes_used) bytes
FROM v$temp_extent_pool
GROUP BY tablespace_name) t,
(SELECT tablespace_name, MAX(bytes_cached) large
FROM v$temp_extent_pool
GROUP BY tablespace_name
order by tablespace_name) l
WHERE d.tablespace_name = a.tablespace_name(+)
AND d.tablespace_name = t.tablespace_name(+)
AND d.tablespace_name = l.tablespace_name(+)
AND d.extent_management LIKE 'LOCAL'
AND d.contents LIKE 'TEMPORARY'
ORDER by 1
二、收缩数据文件
如果通过上述SQL查询出表空间的使用率较低,剩余空间较大,此时我们可以考虑通过收缩数据文件来释放空闲空间。
1.使用 resize check脚本生成执行SQL
可先通过如下脚本查询有哪些数据文件可以释放,该脚本成功执行后会提供可执行的语句,直接复制便可执行已收缩数据文件。
REM Script is meant for Oracle version 9 and higher
REM -----------------------------------------------
set serveroutput on
exec dbms_output.enable(1000000);
declare
cursor c_dbfile is
select f.tablespace_name,f.file_name,f.file_id,f.blocks,t.block_size
,decode(t.allocation_type,'UNIFORM',t.initial_extent/t.block_size,0) uni_extent
,decode(t.allocation_type,'UNIFORM',(128+(t.initial_extent/t.block_size)),128) file_min_size
from dba_data_files f,
dba_tablespaces t
where f.tablespace_name = t.tablespace_name
and t.status = 'ONLINE'
order by f.tablespace_name,f.file_id;
cursor c_freespace(v_file_id in number) is
select block_id, block_id+blocks max_block
from dba_free_space
where file_id = v_file_id
order by block_id desc;
/* variables to check settings/values */
dummy number;
checkval varchar2(10);
block_correction1 number;
block_correction2 number;
/* running variable to show (possible) end-of-file */
file_min_block number;
/* variables to check if recycle_bin is on and if extent as checked is in ... */
recycle_bin boolean:=false;
extent_in_recycle_bin boolean;
/* exception handler needed for non-existing tables note:344940.1 */
sqlstr varchar2(100);
table_does_not_exist exception;
pragma exception_init(table_does_not_exist,-942);
/* variable to spot space wastage in datafile of uniform tablespace */
space_wastage number;
begin
/* recyclebin is present in Oracle 10.2 and higher and might contain extent as checked */
begin
select value into checkval from v$parameter where name = 'recyclebin';
if checkval = 'on'
then
recycle_bin := true;
end if;
exception
when no_data_found
then
recycle_bin := false;
end;
/* main loop */
for c_file in c_dbfile
loop
/* initialization of loop variables */
dummy :=0;
extent_in_recycle_bin := false;
file_min_block := c_file.blocks;
begin
space_wastage:=0; /* reset for every file check */
<<check_free>>
for c_free in c_freespace(c_file.file_id)
loop
/* if blocks is an uneven value there is a need to correct
with -1 to compare with end-of-file which is even */
block_correction1 := (0-mod(c_free.max_block,2));
block_correction2 := (0-mod(c_file.blocks,2));
if file_min_block+block_correction2 = c_free.max_block+block_correction1
then
/* free extent is at end so file can be resized */
file_min_block := c_free.block_id;
/* Uniform sized tablespace check if space at end of file
is less then uniform extent size */
elsif (c_file.uni_extent !=0) and ((c_file.blocks - c_free.max_block) < c_file.uni_extent)
then
/* uniform tablespace which has a wastage of space in datafile
due to fact that space at end of file is smaller than uniform extent size */
space_wastage:=c_file.blocks - c_free.max_block;
file_min_block := c_free.block_id;
else
/* no more free extent at end of file, file cannot be further resized */
exit check_free;
end if;
end loop;
end;
/* check if file can be resized, minimal size of file 128 {+ initial_extent} blocks */
if (file_min_block = c_file.blocks) or (c_file.blocks <= c_file.file_min_size)
then
dbms_output.put_line('Tablespace: '||c_file.tablespace_name||' Datafile: '||c_file.file_name);
dbms_output.put_line('cannot be resized no free extents found');
dbms_output.put_line('Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized');
dbms_output.put_line('.');
else
/* file needs minimal no of blocks which does vary over versions,
using safe value of 128 {+ initial_extent} */
if file_min_block < c_file.file_min_size
then
file_min_block := c_file.file_min_size;
end if;
dbms_output.put_line('Tablespace: '||c_file.tablespace_name||' Datafile: '||c_file.file_name);
dbms_output.put_line('current size: '||(c_file.blocks*c_file.block_size)/1024||'K'||' can be resized to: '||round((file_min_block*c_file.block_size)/1024)||'K (reduction of: '||round(((c_file.blocks-file_min_block)/c_file.blocks)*100,2)||' %)');
/* below is only true if recyclebin is on */
if recycle_bin
then
begin
sqlstr:='select distinct 1 from recyclebin$ where file#='||c_file.file_id;
execute immediate sqlstr into dummy;
if dummy > 0
then
dbms_output.put_line('Extents found in recyclebin for above file/tablespace');
dbms_output.put_line('Implying that purge of recyclebin might be needed in order to resize');
dbms_output.put_line('SQL> purge tablespace '||c_file.tablespace_name||';');
end if;
exception
when no_data_found
then null;
when table_does_not_exist
then null;
end;
end if;
dbms_output.put_line('SQL> alter database datafile '''||c_file.file_name||''' resize '||round((file_min_block*c_file.block_size)/1024)||'K;');
if space_wastage!=0
then
dbms_output.put_line('Datafile belongs to uniform sized tablespace and is not optimally sized.');
dbms_output.put_line('Size of datafile is not a multiple of NN*uniform_extent_size + overhead');
dbms_output.put_line('Space that cannot be used (space wastage): '||round((space_wastage*c_file.block_size)/1024)||'K');
dbms_output.put_line('For optimal usage of space in file either resize OR increase to: '||round(((c_file.blocks+(c_file.uni_extent-space_wastage))*c_file.block_size)/1024)||'K');
end if;
dbms_output.put_line('.');
end if;
end loop;
end;
/
比如执行结果如下:
Tablespace: BLOBS Datafile: /Data/STUDY/datafile/studyblobs01.dbf
current size: 33553408K can be resized to: 33548288K (reduction of: .02 %)
SQL> alter database datafile '/Data/STUDY/datafile/studyblobs01.dbf' resize 33548288K;
.
Tablespace: BLOBS Datafile: /Data/STUDY/datafile/studyblobs02.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: BLOBS Datafile: /Data/STUDY/datafile/studyblobs03.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: INDX Datafile: /Data/STUDY/datafile/studyindex01.dbf
current size: 33553408K can be resized to: 32640000K (reduction of: 2.72 %)
SQL> alter database datafile '/Data/STUDY/datafile/studyindex01.dbf' resize 32640000K;
.
Tablespace: INDX Datafile: /Data/STUDY/datafile/studyindex02.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: SYSAUX Datafile: /Data/STUDY/datafile/studysysaux01.dbf
current size: 4741120K can be resized to: 4734976K (reduction of: .13 %)
SQL> alter database datafile '/Data/STUDY/datafile/studysysaux01.dbf' resize 4734976K;
.
Tablespace: SYSAUX Datafile: /Data/STUDY/datafile/studysysaux02.dbf
current size: 4608000K can be resized to: 4250624K (reduction of: 7.76 %)
SQL> alter database datafile '/Data/STUDY/datafile/studysysaux02.dbf' resize 4250624K;
.
Tablespace: SYSTEM Datafile: /Data/STUDY/datafile/studysystem01.dbf
current size: 1843200K can be resized to: 790528K (reduction of: 57.11 %)
SQL> alter database datafile '/Data/STUDY/datafile/studysystem01.dbf' resize 790528K;
.
Tablespace: UNDOTBS1 Datafile: /Data/STUDY/datafile/studyundotbs01.dbf
current size: 33553408K can be resized to: 2811904K (reduction of: 91.62 %)
SQL> alter database datafile '/Data/STUDY/datafile/studyundotbs01.dbf' resize 2811904K;
.
Tablespace: UNDOTBS1 Datafile: /Data/STUDY/datafile/studyundotbs02.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: USERS Datafile: /Data/STUDY/datafile/studyusers01.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: USERS Datafile: /Data/STUDY/datafile/studyusers02.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: USERS Datafile: /Data/STUDY/datafile/studyusers03.dbf
cannot be resized no free extents found
Note: for some cases, dba_free_spaces data is not accurate, and this script does not work for such cases. You may want to manually check if the datafile is feasible to be resized
.
Tablespace: WCAUDIT Datafile: /Data/STUDY/datafile/studywcaudit01.dbf
current size: 9832064K can be resized to: 9818112K (reduction of: .14 %)
SQL> alter database datafile '/Data/STUDY/datafile/studywcaudit01.dbf' resize 9818112K;
.
PL/SQL procedure successfully completed
SQL>
可提炼出如下 SQL 用以收缩数据文件(根据实际需求选择执行):
SQL> alter database datafile '/Data/STUDY/datafile/studyblobs01.dbf' resize 33548288K;
SQL> alter database datafile '/Data/STUDY/datafile/studyindex01.dbf' resize 32640000K;
SQL> alter database datafile '/Data/STUDY/datafile/studysysaux01.dbf' resize 4734976K;
SQL> alter database datafile '/Data/STUDY/datafile/studysysaux02.dbf' resize 4250624K;
SQL> alter database datafile '/Data/STUDY/datafile/studysystem01.dbf' resize 790528K;
SQL> alter database datafile '/Data/STUDY/datafile/studyundotbs01.dbf' resize 2811904K;
SQL> alter database datafile '/Data/STUDY/datafile/studywcaudit01.dbf' resize 9818112K;
2.通过查询dba_data_files表自己写执行SQL
select file_name,user_bytes from dba_data_files;
比如查询结果中的这一行:
我们可以执行如下语句来收缩表空间:
SQL> alter database datafile ‘/Data/STUDY/datafile/studyblobs01.dbf’ resize 26213351424;
如遇到“ORA-03297: file contains used data beyond requested RESIZE value”错误,可以resize后的值稍微调大一些再次执行。
参考文章:
https://www.cnblogs.com/rangle/p/9263505.html