Featured Database Articles

Oracle: MOVE vs SHRINK Commands

The move command compacts the rows within Oracle blocks, resolves row chaining, and resets a table's High Water Mark

Both the move and shrink commands reset the high water mark of a table, but which command is more efficient? This article discusses re-organizing a table using the move and shrink commands, then compares how the rows are compacted within Oracle blocks and how row chaining is resolved.

Note: It is beyond the scope of this document to present a detailed discussion about the High Water Mark of a table and all of the different methodologies for resetting the High Water Mark of a table.

The following steps briefly describe various operations performed on the table, TEMP_JP, during the re-org of the table using the move and shrink commands. A few exceptions in the series of steps are marked distinctly(Move related commands in BLUE, Shrink related commands in GREEN).

01  03

Created table temp_jp and inserted 2500 rows into the table

04

Displayed the rows distribution in the tables Oracle blocks.

Strangely, the number of rows inserted per Oracle block is not uniform.

05

Indexed my table temp_jp.

06

Verified the disk space usage for the table and index.

By default, Oracle allocates one extent for a table and two extents for an index.

07

Added a third column to temp_jp table to simulate row chaining.

08

Temp_jp table is analyzed.

09

Select the number of rows and number of chained rows from temp_jp table.

Almost all of the rows in the table temp_jp are chained.

10

Verified the disk space usage for the table and index after simulating row chaining.

The disk space usage for the table temp_jp increased by 10 fold.

11

Deleted all rows from the table, leaving one row per Oracle block within the table.

12

Displayed the spread of rows from temp_jp table after deleting records.

The number of rows present per Oracle block are uniform, since we deleted all of the rows from table, leaving one row per Oracle block within the table.

13

Temp_jp table is analyzed.

14

Select number of rows and chained rows from temp_jp table.

15

Verify the status of the index on temp_jp table. Its VALID.

16

16-A

Performed move operation on temp_jp table.

16-BA

16-BB Performed shrink operation on temp_jp table.

17

17-A

The status of the index is unusable after temp_jp tables move operation.

17-BThe status of the index is valid after temp_jp tables shrink operation.

18

Displayed the disk space usage for the temp_jp table and its index.

18-A

After the move operation, one extent was allocated to the table and two for the index.

18-B

After the shrink operation, the table and index are allocated one extent each of 8 Oracle blocks. The initial two extents for the index had come down to one.

19

Displayed the spread of rows within Oracle blocks of temp_jp table.

19-A

All five rows in temp_jp table are compacted into one Oracle block.

19-B

All five rows in temp_jp table are spread into three Oracle blocks.

20

20-AA

Table analyze operation failed, with the error ORA-01502

20-AB

Rebuilt the index on temp_jp table to validate it.

After the index rebuild operation, one Oracle extent was allocated to the index.

declare
begin
for c1 in (select DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) block,
max(rowid) max_rowid
from temp_jp group by DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) loop
for c2 in (select rowid,DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) block
from temp_jp
where DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)=c1.block) loop
if ((c2.block = c1.block) and (c2.rowid <> c1.max_rowid)) then
delete from temp_jp where rowid = c2.rowid;
end if;
end loop;
end loop;
commit;
end;
/

declare
begin
for c1 in (select DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) block,
max(rowid) max_rowid
from temp_jp group by DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) loop
for c2 in (select rowid,DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) block
from temp_jp
where DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)=c1.block) loop
if ((c2.block = c1.block) and (c2.rowid <> c1.max_rowid)) then
delete from temp_jp where rowid = c2.rowid;
end if;
end loop;
end loop;
commit;
end;
/

All of the rows are compacted into one oracle block, after the move operation on temp_jp table. Row chaining is completely resolved in temp_jp table.

The shrink operation could not completely resolve row chaining in the table. The remaining 5 rows in the table are spread across three oracle blocks in the table.

After all the foregoing, in a read intensive application, where milliseconds in performance count, I would vote for the move command. I am prepared to go the extra mile, rebuilding the unusable indexes and provisioning extra disk space for the objects move operation while resetting high water mark.