Oracle Tablespace File Management Made Simple

One of the most common tasks for any DBA is managing the space used by the database.  This, in turn, translates to managing space on the server.  In the early days of Oracle, this could be quite a task as it was considered a ‘best practice’ to use as few extents as possible to cut down on fragmentation.  Also, there were some pretty strong limitations on file sizes, which were enforced at the OS level.  Today, we have locally managed tablespaces and automatic segment management.  These options, coupled with the large file sizes that the typical operating system offers, have freed the DBA from from micromanaging each extent, segment, and file in the database. 

How Big Should My Tablespace Be?

When creating a new tablespace, often one makes space calculations based on information from developers and other application experts.  Often you’re dealing with a purchased package and only have the vendor’s recommendations to go by.  These recommendations or calculations can result in vastly over-allocated space.  A calculation may show that within the first year the tablespace will need be 100Gb to hold all of the data.  Or perhaps, the developer simply requests a 100Gb tablespace based on his or her knowledge of the data.  In any event, you’ve got a tablespace request and, in turn, you request your friendly Unix SA to allocate 100Gb to a filesystem so that this 100Gb tablespace can be accommodated.

SQL> create tablespace appdata datafile ‘/u01/oradata/appdata01.dbf’ size 20g,
 2                                      ‘/u01/oradata/appdata02.dbf’ size 20g,
 3                                      ‘/u01/oradata/appdata03.dbf’ size 20g,
 4                                      ‘/u01/oradata/appdata04.dbf’ size 20g,
 5                                      ‘/u01/oradata/appdata05.dbf’ size 20g ;
 
Tablespace created.

As time goes on, you receive no space alerts for this tablespace, but like a good DBA you log in and check on the freespace from time to time. After a year, you find only 20Gb occupied.  The tables have not grown at the rate that was expected and you have tied up 80Gb unnecessarily. 

Autoextensible Files

So, what do we do when a tablespace is requested but there is no real good idea of how much data may be going into it?  To the rescue come autoextensible files.

SQL> create tablespace mytbs datafile 
 2   ‘/u01/oradata/mytbs01.dbf’ size 1g autoextend on next 1g maxsize 20g,
 3   ‘/u01/oradata/mytbs02.dbf’ size 1g autoextend on next 1g maxsize 20g,
 4   ‘/u01/oradata/mytbs03.dbf’ size 1g autoextend on next 1g maxsize 20g,
 5   ‘/u01/oradata/mytbs04.dbf’ size 1g autoextend on next 1g maxsize 20g,
 6   ‘/u01/oradata/mytbs05.dbf’ size 1g autoextend on next 1g maxsize 20g ;
 
 
Tablespace created.

This time, we have created a tablespace that is 5Gb in size with the capability to grow to 100Gb.  Monitoring the filesystem at the OS level is now just as effective as monitoring the free space in the tablespace itself.  In many ways it is MORE effective as tablespace freespace may be made up of many small unusable chunks (in which case, you may need to reorg—but that’s another topic).

Checking Available Space

When checking for the available space, you now need to distinguish between “allocated” space versus “physically allocated” space.  I’ve found that this trips people up as the tendency is to look at dba_free_space.  In our example above, we have allocated 100Gb, but we have only physically allocated 5Gb.  The below query looks at dba_free_space and reflects only the physically allocated space. 

SQL> l
  1  select a.tablespace_name, a.bytes_alloc, nvl(b.tot_free, 0) tot_free,
  2         a.bytes_alloc-nvl(b.tot_free,0) tot_used, nvl(b.max_free_extent,0) max_free_extent,
  3        ((a.bytes_alloc-nvl(b.tot_free,0))/a.bytes_alloc)*100 pct_used
  4  from ( select tablespace_name, sum(bytes) bytes_alloc
  5           from dba_data_files
  6          group by tablespace_name ) a,
  7       ( select tablespace_name, sum(bytes) tot_free, max(bytes) max_free_extent
  8           from dba_free_space
  9          group by tablespace_name ) b,
 10        dba_tablespaces c
 11  where a.tablespace_name = b.tablespace_name (+)
 12  and   a.tablespace_name = c.tablespace_name
 13  union
 14  select a.tablespace_name, sum(bytes) bytes_alloc, null, null, null, null
 15  from   dba_temp_files a, dba_tablespaces c
 16  where  a.tablespace_name = c.tablespace_name
 17  group by a.tablespace_name, c.status
 18* order by 1
SQL> /
 
TABLESPACE_NAME                 BYTES_ALLOC         TOT_FREE             TOT_USED  MAX_FREE_EXTENT PCT_USED 
---------------------- -------------------- ---------------- -------------------- ---------------- -------- 
MYTBS                         5,368,709,120    5,363,466,240            5,242,880    1,072,693,248      .10
SYSAUX                          786,432,000       53,870,592          732,561,408       45,088,768    93.15 
SYSTEM                          377,487,360        5,439,488          372,047,872        5,242,880    98.56 
TEMP                             20,971,520                                                                 
UNDOTBS1                         89,128,960       78,249,984           10,878,976       63,963,136    12.21 
USERS                           104,857,600      102,170,624            2,686,976      102,105,088     2.56 

Here we will show the allocated versus the physically allocated space:

SQL> l
  1  select a.tablespace_name,
  2         a.bytes_alloc/(1024*1024) "TOTAL ALLOC (MB)",
  3         a.physical_bytes/(1024*1024) "TOTAL PHYS ALLOC (MB)",
  4         nvl(b.tot_used,0)/(1024*1024) "USED (MB)",
  5         (nvl(b.tot_used,0)/a.bytes_alloc)*100 "% USED"
  6  from ( select tablespace_name,
  7         sum(bytes) physical_bytes,
  8         sum(decode(autoextensible,'NO',bytes,'YES',maxbytes)) bytes_alloc
  9         from dba_data_files
 10         group by tablespace_name ) a,
 11       ( select tablespace_name, sum(bytes) tot_used
 12         from dba_segments
 13         group by tablespace_name ) b
 14  where a.tablespace_name = b.tablespace_name (+)
 15* and   a.tablespace_name not in (select distinct tablespace_name from dba_temp_files) 
SQL> /
 
TABLESPACE_NAME        TOTAL ALLOC (MB) TOTAL PHYS ALLOC (MB)     USED (MB)  % USED
---------------------- ---------------- --------------------- ------------- -------
MYTBS                        102,400.00              5,120.00          0.00    0.00 
SYSAUX                        32,767.98                750.00        697.63    2.13
SYSTEM                           600.00                360.00        353.81   58.97
UNDOTBS1                      32,767.98                 85.00          9.38    0.03
USERS                         11,264.00                100.00          1.56    0.01

Note the total allocated space is 100Gb while the physically allocated space is 5Gb.  Let’s put something in our tablespace and see what things look like:

SQL> create table mmtest (x number) storage (initial 4g next 128m) tablespace mytbs;
 
Table created.
 
SQL> @tsinfo
 
TABLESPACE_NAME                 BYTES_ALLOC         TOT_FREE             TOT_USED  MAX_FREE_EXTENT PCT_USED 
---------------------- -------------------- ---------------- -------------------- ---------------- -------- 
MYTBS                         5,368,709,120    1,068,498,944        4,300,210,176      264,241,152    80.10 
SYSAUX                          786,432,000       53,870,592          732,561,408       45,088,768    93.15 
SYSTEM                          377,487,360        5,439,488          372,047,872        5,242,880    98.56 
TEMP                             20,971,520                                                                 
UNDOTBS1                         89,128,960       78,249,984           10,878,976       63,963,136    12.21 
USERS                           104,857,600      102,170,624            2,686,976      102,105,088     2.56 
 
SQL> @tsalloc
 
TABLESPACE_NAME        TOTAL ALLOC (MB) TOTAL PHYS ALLOC (MB)     USED (MB)  % USED
---------------------- ---------------- --------------------- ------------- -------
MYTBS                        102,400.00              5,120.00      4,096.00    4.00 
SYSAUX                        32,767.98                750.00        697.63    2.13
SYSTEM                           600.00                360.00        353.81   58.97
UNDOTBS1                      32,767.98                 85.00          9.38    0.03
USERS                         11,264.00                100.00          1.56    0.01

 

If we look at things from a strictly “physical” point of view (using the 1st query), the tablespace appears to be 80% full.  However, if we take the autoextensible files into account (using the 2nd query), we can see that the tablespace is only 4% full!  The tablespace can continue to fill and to grow and we need only monitor the filesystem.  At some point, of course, additional files may need to be added, but you can follow the same strategy there:

SQL> alter tablespace mytbs add datafile ‘/u01/oradata/mytbs06.dbf’ size 1g autoextend on next 1g maxsize unlimited ;
 
Tablespace altered.

Monitor the Files—Not the Free Space

There are no hard and fast rules for the initial size you give the file and at what size you specify the ‘next’ parameter.  Often choosing a smaller number (100M) will make more sense.  Choosing ‘maxsize unlimited’ is often the simplest choice.  Don’t worry, Oracle doesn’t actually grow the file ad infinitum if you specify ‘unlimited’.  The maxsize is OS dependant and is limited by the maximum operating system file size.  The easiest way to be certain what it is exactly is to query the database:

SQL> l
  1  select file_id, file_name, bytes/1024/1024 mbytes, autoextensible, maxbytes/1024/1024 max_mbytes,
  2         increment_by*block_size/1024/1024 increment_by_mbytes,
  3         substr(file_name, instr(file_name,'/',-1)+1, length(file_name)) fn
  4  from dba_data_files f, dba_tablespaces t
  5  where f.tablespace_name = trim(upper('&&ts'))
  6  and   f.tablespace_name = t.tablespace_name
  7  union
  8  select file_id, file_name, bytes/1024/1024 mbytes, autoextensible, maxbytes/1024/1024 max_mbytes,
  9         increment_by*block_size/1024/1024 increment_by_mbytes,
 10         substr(file_name, instr(file_name,'/',-1)+1, length(file_name)) fn
 11  from dba_temp_files f, dba_tablespaces t
 12  where f.tablespace_name = trim(upper('&&ts'))
 13  and   f.tablespace_name = t.tablespace_name
 14* order by file_id
SQL> /
Enter value for ts: mytbs
 
   FILE_ID FILE_NAME                           MBYTES AUT MAX_MBYTES INCREMENT_BY_MBYTES
---------- ----------------------------- ------------ --- ---------- -------------------
        12 /u01/oradata/mytbs01.dbf             1,024 YES     20,480               1,024
        13 /u01/oradata/mytbs01.dbf             1,024 YES     20,480               1,024
        14 /u01/oradata/mytbs01.dbf             1,024 YES     20,480               1,024
        15 /u01/oradata/mytbs01.dbf             1,024 YES     20,480               1,024
        16 /u01/oradata/mytbs01.dbf             1,024 YES     20,480               1,024
        17 /u01/oradata/mytbs01.dbf             1,024 YES     32,768               1,024

So, the new file that was added later with ‘maxsize unlimited’ actually has a maximum size 32Gb. 

Using this strategy with autoextensible files can simplify your life as a DBA.  There are DBAs out there that believe that this is a lazy way of managing tablespaces–and space in general.  However, I believe that it just makes sense.  So often we have no way of knowing how much space is going to be required in a given tablespace.  Over-allocating the space up front is a waste.  Using it as you need it is smart!

See all articles by Mary Mikell Spence

Mary Mikell Spence
Mary Mikell Spence
Mary Mikell Spence, a Senior Oracle Database Administrator living in Metropolitan Atlanta, Georgia, has worked in the IT field since graduating from Georgia Tech in 1983. Beginning her career as an application developer, she has worked with Oracle since 1991. Her Oracle experience encompasses database design and architecture, development, production support, backup and recovery as well as Oracle E-Business Suite. Mary may be found on LinkedIn at http://www.linkedin.com/in/mmspence.

Get the Free Newsletter!

Subscribe to Cloud Insider for top news, trends & analysis

Latest Articles