Professional Documents
Culture Documents
Question: How Do I Reduce The Size of My Oracle Data File Sizes? I Want To Shrink The Size of My
Question: How Do I Reduce The Size of My Oracle Data File Sizes? I Want To Shrink The Size of My
Where name is the name of the database, file_name is the name of the file and size is the new
size to make this file. We can see this size change in the dba_data_files table as well as from
the server.
First, pull in the database name:
Select 'alter database '||a.name
From v$database a;
Once that has been done, it's time to add in data files:
select 'alter database '||a.name||' datafile '''||b.file_name||''''
from v$database a
,dba_data_files b;
While this is closer to the ultimate solution, it's not quite there yet. The question remains:
Which data files do you want to alter? At this point, you can use a generally accepted
standard, which allows tablespaces to be 70 percent to 90 percent full. If a tablespace is below
the 70 percent mark, one way to bring the number up is to de-allocate some of the space.
So how do you achieve percent full? While there are a number of different ways, simple is
usually ideal. Here's how it works.
Amount of data file space used:
Select tablespace_name,sum(bytes) bytes_full
From dba_extents
Group by tablespace_name;
So if we add this with our original statement, we can select on pct_used (less than 70 percent):
select 'alter database '||a.name||' datafile '''||b.file_name||''''
from v$database a
,dba_data_files b
,(Select tablespace_name,sum(bytes) bytes_full
From dba_extents
Group by tablespace_name) c
,(Select tablespace_name,sum(bytes) bytes_total
From dba_data_files
Group by tablespace_name) d
Where b.tablespace_name = c.tablespace_name
And b.tablespace_name = d.tablespace_name
And bytes_full/bytes_total < .7
;
According to the command, a selection has been made based on tablespace. What if you want
to resize based on file? It's crucial to remember that multiple files can exist in any tablespace.
Plus, only space that is after the last data block can be de-allocated. So the next step should be
to find the last data block:
select tablespace_name,file_id,max(block_id) max_data_block_id
from dba_extents
group by tablespace_name,file_id;
Now that the command to find the last data block has been inserted, it is time to find the free
space in each file above that last data block:
Select a.tablespace_name,a.file_id,b.bytes bytes_free
From (select tablespace_name,file_id,max(block_id) max_data_block_id
from dba_extents
group by tablespace_name,file_id) a
,dba_free_space b
where a.tablespace_name = b.tablespace_name
and a.file_id = b.file_id
and b.block_id > a.max_data_block_id;
So far, so good. How is it possible, then, to combine commands to ensure the correct amount
will be resized? In fact, it's fairly easy.
select 'alter database '||a.name||' datafile '''||b.file_name||'''' ||
' resize '||(bytes_total-bytes_free)
from v$database a
,dba_data_files b
,(Select tablespace_name,sum(bytes) bytes_full
From dba_extents
Group by tablespace_name) c
,(Select tablespace_name,sum(bytes) bytes_total
From dba_data_files
Group by tablespace_name) d
,(Select a.tablespace_name,a.file_id,b.bytes bytes_free
From (select tablespace_name,file_id
,max(block_id) max_data_block_id
from dba_extents
group by tablespace_name,file_id) a
,dba_free_space b
where a.tablespace_name = b.tablespace_name
and a.file_id = b.file_id
and b.block_id > a.max_data_block_id) e
Where b.tablespace_name = c.tablespace_name
And b.tablespace_name = d.tablespace_name
;
One last thing to do: Add a statement to indicate what is being changed.
select 'alter database '||a.name||' datafile '''||b.file_name||'''' ||
' resize '||greatest(trunc(bytes_full/.7)
,(bytes_total-bytes_free))||chr(10)||
'--tablespace was '||trunc(bytes_full*100/bytes_total)||
'% full now '||
trunc(bytes_full*100/greatest(trunc(bytes_full/.7)
,(bytes_total-bytes_free)))||'%'
from v$database a
,dba_data_files b
,(Select tablespace_name,sum(bytes) bytes_full
From dba_extents
Group by tablespace_name) c
,(Select tablespace_name,sum(bytes) bytes_total
From dba_data_files
Group by tablespace_name) d
,(Select a.tablespace_name,a.file_id,b.bytes bytes_free
From (select tablespace_name,file_id
,max(block_id) max_data_block_id
from dba_extents
group by tablespace_name,file_id) a
,dba_free_space b
where a.tablespace_name = b.tablespace_name
and a.file_id = b.file_id
and b.block_id > a.max_data_block_id) e
Where b.tablespace_name = c.tablespace_name
And b.tablespace_name = d.tablespace_name
And bytes_full/bytes_total < .7
And b.tablespace_name = e.tablespace_name
And b.file_id = e.file_id
;
At last, here's a script that will create the script. Even so, it's important to pay careful attention
when applying the created script. Why? Because Rollback, System and Temporary tablespaces
are vastly different creatures, and each should not necessarily be held to the 70 percent rule. By
the same token, there might be a very good reason for a tablespace to be over allocated -- like the
giant load that will triple the volume tonight.
A word of caution, too: Be sure that extents can still be allocated in each tablespace. There may
be enough free space, but it may be too fragmented to be useful. That problem will be the focus
of another article.