- 📈 Oracle LOBs stored out-of-line may use whole blocks per entry—even if the LOB is small.
- ⚠️ Default BASICFILE LOBs don't have compression and can make tablespace use much bigger.
- 🧱 Oracle block overhead, like information about the block and transactions, quietly uses up large parts of each block.
- 🗃️ Partitioned tables set aside space beforehand, even when there is no data yet—this wastes space.
- 🔍 Delayed segment creation can still cause permanent space use through temporary inserts or LOBs.
Introduction
Even in Oracle databases that don't have much traffic or data, tablespaces sometimes get much bigger than expected. Developers wonder why simple database setups end up using gigabytes of disk space with seemingly little data to show for it. Why? Often it's hidden in Oracle's default settings for LOB storage, information stored at the block level, and segment behavior you don't see. In this guide, we explain the technical reasons that cause unexpected Oracle tablespace growth, how specific storage settings affect space use, and what you can do about tablespaces that have grown too big.
Understanding Oracle Tablespace and Storage Layers
An Oracle tablespace is the logical place where all database objects like tables, indexes, and LOB data live. Looking at how storage is set up, a tablespace is made of one or more physical datafiles. These datafiles hold the internal parts of Oracle’s storage setup:
- Segments: A logical group of extents set aside for a specific type of object, like a table or index.
- Extents: A connected block of storage space given to a segment based on what it needs.
- Blocks: The basic part Oracle reads or writes, which holds actual data rows—and naturally includes some extra space for internal use.
This layered way of assigning space helps manage data well, but it also makes things more complicated. If you don't clearly understand how these layers work together, you will get unexpected bloat.
Also, when you insert a row, Oracle doesn't just store the data. It sets aside space for internal information, like transaction slots (ITLs), block headers, and information about the row itself. You can't always see this Oracle block overhead with regular queries, but it adds a lot to the total disk space used.
Large Object (LOB) Storage & Misconfiguration Pitfalls
LOBs (large objects), such as BLOBs (binary data), CLOBs (text data), and NCLOBs (national character sets), use a lot of storage space in Oracle. They are especially hard to manage because the default settings are not always obvious, and many settings change how they act.
In-Row vs. Out-of-Row LOB Storage
By default:
- LOBs smaller than 4KB may be stored right with the table row (this depends on the block size and the
ENABLE STORAGE IN ROWsetting). - If the LOB is larger than the block limit or if
DISABLE STORAGE IN ROWis used, the LOB is stored separately in its own LOB segment.
The risk is in how Oracle sets aside space:
- Each LOB stored outside the row causes at least one block (usually 8KB) to be set aside, even if the actual data is only a few bytes.
- This means storing thousands of small images or JSON data in a LOB column with the wrong settings can use up gigabytes quickly.
SECUREFILE vs. BASICFILE LOBs
The BASICFILE LOB storage option was the default in older Oracle versions, but now it's considered old. Its limits include:
- It doesn't support removing duplicate data.
- It has little or no compression.
- It requires more reading and writing because it doesn't put data inline well.
Newer Oracle versions support SECUREFILE LOBs, which offer:
- Built-in ways to compress data (
COMPRESS,HIGH, orMEDIUMmodes). - Better duplicate data removal.
- Faster access and more efficient storage, even for lots of similar content.
If you don't clearly say to use SECUREFILE, Oracle often uses BASICFILE instead. This leads to space being used unnecessarily.
What You Should Check
Here are the common mistakes and default settings to check:
- Is the column set with
ENABLE STORAGE IN ROWfor small data? - Are you using
SECUREFILEwith compression turned on the right way? - Are
NOCACHEandNOLOGGINGset for data that doesn't change often? - Are temporary LOBs being released using
DBMS_LOB.freetemporary()after you are done with them?
Oracle Block Overhead – The Hidden Space Eater
The size of single Oracle data blocks might make you think they can hold a lot of data, but that's not always true. Part of every block is saved for these things:
- Block Header: Stores information about the block's status and how data is organized inside it.
- ITLs (Interested Transaction Lists): Hold details about different database tasks happening at the same time that affect rows in the block.
- Row Directory and Metadata: Keeps track of where each row is in the block and its status.
- Free Space: Kept based on the PCTFREE settings for the table to allow data in the block to grow later.
In reality, this means:
- An 8KB block might only give you 6–6.5KB of space for your actual data.
- Workloads that involve lots of updates, inserts, and deletes create row pieces and old row versions.
- When blocks split, especially in index structures, this causes more overhead and space that isn't used.
When you have millions of rows, this Oracle block overhead adds up a lot. This is particularly true for tables with big or often changing rows. This can cause rows to be chained or moved, and each of these uses more space and slows things down.
Partitions, Unused Segments, and Ghost Allocations
When you use partitioned tables or indexes, it's easy to guess wrong about how much disk space you need. Every partition works like a regular object—it gets its own segment.
Partition Storage Characteristics
- Initial Extent Allocation: Oracle usually sets aside space for partitions right away, even if they have no data.
- Hundreds of Partitions = Hundreds of Segments: Partitions made automatically (like for daily logs) use disk space, even when they aren't active.
- Extent Management Settings: If you use
UNIFORM SIZEextents, every new partition reserves a fixed block of space—potentially wasting MBs for each partition.
If you create partitions early (like for date-range tables) well before they are needed, the unused segments that pile up start using your tablespace without holding any actual data.
Ghost Allocations in Dev/QA
In non-production environments:
- Adding and removing test records can result in space being used that doesn't get returned.
- Development tools that move objects often create segments right away, and these segments stay there after you finish testing.
- Mistakes in how partition keys are set up can create unexpected partitions with nothing set up to clean them up.
Every test run in QA that doesn't get cleaned up enough can slowly make the tablespace grow.
How Delayed Segment Creation Tricks You
Starting with Oracle 11g, delayed segment creation was added to make better use of storage. It waits to actually set aside the segment space until you put the first row into the table. This is good for performance and using less space in places with little data, but it also hides problems:
- Temporary Data Still Starts Segment Creation: Did you fill and then clear a table in one session? The segment stays there forever.
- LOB Insertions Always Start Allocations: Even very small LOB content causes the full LOB segment to be created.
- Undo and Flashback Issues: Undo records linked to activity from tables you dropped can stay if
UNDO_RETENTIONis set high.
If you don't actively shrink, truncate, or remove test data segments, unused data builds up in the background.
Using SQL To Check Rapid Tablespace Growth
Finding out why tablespaces are growing big means looking closely at the segment level. Here are two very helpful queries:
General Segment Usage
SELECT segment_name, segment_type, SUM(bytes)/1024/1024 AS mb
FROM dba_segments
WHERE tablespace_name = 'USERS'
GROUP BY segment_name, segment_type
ORDER BY mb DESC;
- Shows if tables, indexes, or LOB segments are using most of the storage.
- Is useful for finding things that use space but you might not have expected, like bitmap indexes or materialized views.
Check LOB Storage Configuration
SELECT table_name, segment_name, securefile, in_row, chunk, pctversion, retention
FROM dba_lobs
WHERE tablespace_name = 'USERS';
- Shows which LOBs are using the old
BASICFILEmethod. - Points out if the default
IN ROWsettings might be used wrong. - Looks at PCTVERSION and RETENTION settings to make undo segment overhead better.
Also think about running this query:
SELECT table_name, column_name, logging, cache, storage
FROM user_lobs;
To check if NOLOGGING and NOCACHE are being set correctly.
Redo Logging and Undo Retention Side Effects
Undo and redo operations don't add directly to the size of user tablespaces, but they do change how segments act a lot:
- High Undo Retention Values (like 10,800 seconds) let Oracle keep old copies of data pages for flashback or rollback features. This makes undo segments larger.
- Redo Generation During LOB Inserts: If you don't use
NOLOGGING, every insert—even of temporary or unchanged data—creates many redo logs. - Flashback Database or Flashback Table needs these segments. This makes Oracle keep changes that would have been removed otherwise.
If you don't use flashback or need undo for a long time, lowering the UNDO_RETENTION setting and compressing undo tablespaces can lessen this space load that isn't directly visible.
Good Practices for LOB Management
Designing and managing LOBs the right way can cut tablespace use by 70% or more. Follow these steps:
- ✅ Store Small LOBs Inline: Use
ENABLE STORAGE IN ROWcarefully so you don't get space problems. - ✅ Use
SECUREFILEwith Compression: This is especially true for lots of text—it makes a big difference in how much space you use. - ✅ Avoid Logging When It's Not Needed:
NOLOGGINGandNOCACHEreally help save space for static document libraries. - ✅ Shrink Segment Space: Run
ALTER TABLE ... MODIFY LOB ... SHRINK SPACEregularly to get back space from LOB segments that aren't fully used. - ✅ Use Temporary LOBs Wisely: Release temporary LOBs yourself with
DBMS_LOB.FREETEMPORARY.
Ways To Get Space Back
If your tablespaces have already gotten too big, several commands can help get that space back:
Release Temporary LOBs
DBMS_LOB.freetemporary(lob_variable);
Shrink LOB Segment Space
ALTER TABLE your_table MODIFY LOB(lob_column) (SHRINK SPACE);
Convert Old LOBs to Compressed SECUREFILE
ALTER TABLE your_table MOVE LOB(lob_column) STORE AS (SECUREFILE COMPRESS);
Move Tables That Are Fragmented
ALTER TABLE your_table MOVE;
Adding these to your regular database maintenance can stop tablespace growth from getting out of control after many inserts, deletes, or updates.
Steps To Stop Tablespace Bloat
The best way to fix it is to stop it before it happens. Before you set up new columns or tables:
- 🎯 Set Up LOBs Clearly: Don't just use the default storage settings; define settings that make sense for how the data will actually be used.
- 📊 Check Segment Usage: Set up checks every month using
DBA_SEGMENTS,DBA_LOBS, andDBA_HIST_*views. - ⚙️ Partition Smartly: Don't make partitions before you need them; use interval partitioning if you can.
- 🧠 Teach Teams About How Oracle Works Inside: Teach developers what default settings like
BASICFILE,IN ROW, andUNDO_RETENTIONactually mean when the database is running.
When people actively plan how to set up the database, it helps keep storage use under control as things grow.
Oracle tablespaces grow quickly because of small mistakes in settings that you often don't see. Maybe it's LOB segments quietly using blocks, or rows getting chained because of block overhead, or segments made later that stay used even after they're not needed. The problem is usually not just "large data". You need to understand how Oracle manages space inside, and make sure your database setup follows good methods. This is the only way to stop tablespaces from exploding before it becomes a big problem.
Citations:
Oracle Corporation. (n.d.). Managing Data in Oracle. Oracle Documentation. Retrieved from https://docs.oracle.com
Oracle Corporation. (n.d.). SQL Language Reference – CREATE TABLE. Oracle Docs. Retrieved from https://docs.oracle.com