Question: How do I reduce the size of
my Oracle data file sizes? I want to shrink the size
of my data files to reclaim un-used space. How do I
reduce the file sizes?
Answer:
(by John Weeg) You can start reducing the size of your
Oracle database files by setting Free Your Space
Conventional database wisdom dictates
that we should treat disk space as though it were free, unfettered space
waiting to be filled with data. It's a liberating idea, but not entirely
practical. Not surprisingly, it's also rife with potential problems. Get
too comfortable with the idea of space being "free" and you may suddenly
find yourself scrounging around for it.
When setting up a
database, for example, a database administrator usually takes educated
guesses at the company's space needs, large or small. It's important to
point out, however, that those guesses tend to be conservative. The
reason? By overestimating the amount of space needed, the administrator is
less likely to wind up stuck when he or she first loads all the data. Once
the instance runs for a while, it's possible to see just how far off the
original estimate of space requirements was. Moreover, the administrator
can give back some of that space.
Over-allocation of space at the
file level affects the backup/recovery window, file checking times and,
most painfully, limits the potential allocation of space to a tablespace
that needs the extra room. A simpler solution would be to review the
evolution of the script, which lets the administrator know which files can
and cannot be resized to create more space.
Alter Database
It's
possible to release space from data files but only down to the first block
of data. This is done with the 'alter database' command. Rather than go
through the tedious process of manually figuring out the command every
time it's used, it makes more sense to write a script that will generate
this command as needed.
The basic syntax for this command is:
Alter database
name datafile 'file_name' resize size;
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;
Total available data file space:
Select
tablespace_name,sum(bytes) bytes_total
From dba_data_files
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
Double Checking the Data file shrink
Now, the thing to do is ensure that the right amount of space - not too
much, not too little - has been de-allocated. The rule of thumb to follow:
Do not go above 70 percent of the tablespace being used. If you have
already pulled out how much is used from
dba_extents, you can simply add
a check to your statement: