ALTER TABLE ... SHRINK SPACE Command : Online Segment Shrink for Tables, LOBs and IOTs
ALTER TABLE ... SHRINK SPACE command was introduced in Oracle 10g to perform online segment shrinks for tables, LOBs and IOT overflow segments.
- Shrink Space Examples
- Identify Large Segments
- Row Movement
- SecureFile LOBs
- Comments and Restrictions
Shrink Space Examples
Here are some simple examples of the
ALTER TABLE ... SHRINK SPACE command.
-- Enable row movement. ALTER TABLE scott.emp ENABLE ROW MOVEMENT; -- Recover space and amend the high water mark (HWM). ALTER TABLE scott.emp SHRINK SPACE; -- Recover space, but don't amend the high water mark (HWM). ALTER TABLE scott.emp SHRINK SPACE COMPACT; -- Recover space for the object and all dependant objects. ALTER TABLE scott.emp SHRINK SPACE CASCADE;
COMPACT option allows the shrink operation to be broken into two stages. First the rows are moved using the
COMPACT option but the high water mark (HWM) is not adjusted so no parsed SQL statements are invalidated. The HWM can be adjusted at a later date by reissuing the statement without the
COMPACT option. At this point any dependent SQL statements will need to be re-parsed.
Other shrink commands of interest are displayed below.
-- Shrink a LOB segment (basicfile only). ALTER TABLE table_name MODIFY LOB(lob_column) (SHRINK SPACE); ALTER TABLE table_name MODIFY LOB(lob_column) (SHRINK SPACE CASCADE); -- Shrink an IOT overflow segment. ALTER TABLE iot_name OVERFLOW SHRINK SPACE;
There is more detail about this functionality below.
Identify Large Segments
DBA|ALL|USER_SEGMENTS views can be used to identify large segments. The following example uses a top-n query to display the 20 largest segments.
SET LINESIZE 200 COLUMN owner FORMAT A30 COLUMN segment_name FORMAT A30 COLUMN tablespace_name FORMAT A30 COLUMN size_mb FORMAT 99999999.00 SELECT * FROM (SELECT owner, segment_name, segment_type, tablespace_name, ROUND(bytes/1024/1024,2) size_mb FROM dba_segments ORDER BY 5 DESC) WHERE ROWNUM <= 20;
You may see many of the larger segments being LOB segments. You can get more information about LOB segments specifically using the following top-n query.
SET LINESIZE 200 COLUMN owner FORMAT A30 COLUMN table_name FORMAT A30 COLUMN column_name FORMAT A30 COLUMN segment_name FORMAT A30 COLUMN tablespace_name FORMAT A30 COLUMN size_mb FORMAT 99999999.00 SELECT * FROM (SELECT l.owner, l.table_name, l.column_name, l.segment_name, l.tablespace_name, ROUND(s.bytes/1024/1024,2) size_mb FROM dba_lobs l JOIN dba_segments s ON s.owner = l.owner AND s.segment_name = l.segment_name ORDER BY 6 DESC) WHERE ROWNUM <= 20;
The following scripts are examples of these types of queries.
ALTER TABLE ... SHRINK SPACE command moves rows between blocks to compact the data, so before you attempt to shrink a table segment you need to enable row movement. You can check if row movement is already enabled by querying the
ROW_MOVEMENT column of the
SELECT row_movement FROM user_tables WHERE table_name = 'EMP'; ROW_MOVE -------- DISABLED SQL>
Row movement is enabled with the following command.
ALTER TABLE emp ENABLE ROW MOVEMENT;
Repeating the previous query shows row movement is now enabled.
SELECT row_movement FROM user_tables WHERE table_name = 'EMP'; ROW_MOVE -------- ENABLED SQL>
When using basicfile LOBs the shrink commands work as expected. To demonstrate this we need to create the following table containing a basicfile LOB column.
DROP TABLE lob_tab PURGE; CREATE TABLE lob_tab ( id NUMBER, data CLOB ) LOB(data) STORE AS BASICFILE (DISABLE STORAGE IN ROW); INSERT INTO lob_tab VALUES (1, 'ONE'); COMMIT;
We can see both shrink commands complete without errors.
SQL> ALTER TABLE lob_tab MODIFY LOB(data) (SHRINK SPACE); Table altered. SQL> ALTER TABLE lob_tab MODIFY LOB(data) (SHRINK SPACE CASCADE); Table altered. SQL>
Now recreate the table using a securefile LOB column.
DROP TABLE lob_tab PURGE; CREATE TABLE lob_tab ( id NUMBER, data CLOB ) LOB(data) STORE AS SECUREFILE (DISABLE STORAGE IN ROW); INSERT INTO lob_tab VALUES (1, 'ONE'); COMMIT;
Now the first command fails, but adding the
CASCADE option appears to make it work.
SQL> ALTER TABLE lob_tab MODIFY LOB(data) (SHRINK SPACE); ALTER TABLE lob_tab MODIFY LOB(data) (SHRINK SPACE) * ERROR at line 1: ORA-10635: Invalid segment or tablespace type SQL> ALTER TABLE lob_tab MODIFY LOB(data) (SHRINK SPACE CASCADE); Table altered. SQL>
Unfortunately, the second command doesn't work and the securefile LOB segment is not shrunk.
Instead, to shrink a securefile LOB segment you need to move it. In the following example the move is to the same tablespace.
ALTER TABLE lob_tab MOVE LOB(data) STORE AS (TABLESPACE users);
Comments and Restrictions
Here are some things to consider before performing shrink operations.
- Moving rows can cause problem with rowid based triggers.
- Rowid materialized views must be rebuilt after a shrink operation.
- The shrinking process is only available for objects in tablespaces with automatic segment-space management enabled.
- You can't combine the
SHRINK SPACEclause with any other
- You can't shrink a cluster or a clustered table.
- You can't shrink any object with a
- You can't shrink tables with dependent function-based indexes, domain indexes, or bitmap join indexes.
- You can't shrink tables that are the master table of an
ON COMMITmaterialized view
- Mapping tables of index-organized tables are not affected by a shrink.
- Shrinks can't be used for compressed tables, except those using Advanced Row Compression (ROW STORE COMPRESS ADVANCED).
- The shrink operation against a table doesn't cascade to the LOB segments. They need to handled separately.
- You can't shrink securefile LOB segments.
- Changing the arrangement of rows in a table can have a negative impact on performance in some circumstances. Test thoroughly before making any decisions.
- Prior to Oracle 12.2 a shrink operation won't necessarily move rows to blocks at the start of a datafile, so it may not be of much help if you are trying to reduce the size of a datafile. Oracle 12.2 encourages this type of shrink.
- After any structural change, like a move, remember to check for unusuable indexes. You can use the unusuable_indexes.sql script to find them. If you have any, rebuild them.
For more information see:
Hope this helps. Regards Tim...