Database in the daily use of the process, continuous insert,delete,update operation, resulting in the table and index fragmentation is inevitable, fragmentation is more, SQL execution efficiency naturally poor, the reason is very simple, high watermark (HWL) Many data blocks are no data, But the full table scan to scan to the high watermark data block, that is to say Oracle to do a lot of useless! As a result, Oracle provides shrink space defragmentation capabilities. For indexes, you can take rebuild online defragmentation, in general, the objects that are frequently DML operations are regularly maintained by DBAs, while keeping in mind that statistics are updated in a timely manner!
One: Prepare test data, use HR user, create T1 table, insert approximately 30W of data, and create normal index according to object_id, table occupies 34M of storage space, index occupies about 6M storage space
- SQL> Conn/as sysdba
- is connected.
- SQL> select Default_tablespace from dba_users where username=' HR ';
- Default_tablespace
- ------------------------------------------------------------
- USERS
- SQL> Conn hr/hr
- is connected.
- SQL> INSERT INTO T1 select * from T1;
- 74812 rows have been created.
- SQL> INSERT INTO T1 select * from T1;
- 149624 rows have been created.
- SQL> commit;
- Submit complete.
- SQL> CREATE index idx_t1_id on T1 (object_id);
- The index has been created.
- SQL> Exec dbms_stats.gather_table_stats (' HR ', ' T1 ',cascade=>true);
- The PL/SQL process has completed successfully.
- SQL> select COUNT (1) from T1;
- COUNT (1)
- ----------
- 299248
- SQL> select sum (bytes)/1024/1024 from dba_segments where segment_name=' T1 ';
- SUM (BYTES)/1024/1024
- --------------------
- 34.0625
- SQL> select sum (bytes)/1024/1024 from dba_segments where segment_name=' idx_t1_id ';
- SUM (BYTES)/1024/1024
- --------------------
- 6
Second: Estimate how much space is available under the high watermark, the lower the better, the higher the table usage is to the high watermark, the less work done by the full table scan!
Dbms_stats package cannot get empty_blocks statistics, so you need to collect statistics with analyze command again
- SQL> SELECT blocks, Empty_blocks, num_rows from user_tables WHERE table_name =' T1 ';
- BLOCKS Empty_blocks Num_rows
- ---------- ------------ ----------
- 4302 0 299248
- SQL> Analyze table T1 compute statistics;
- Table has been analyzed.
- SQL> SELECT blocks, Empty_blocks, num_rows from user_tables WHERE table_name =' T1 ';
- BLOCKS Empty_blocks Num_rows
- ---------- ------------ ----------
- 4302 50 299248
- SQL> Col table_name for A20
- SQL> SELECT table_name,
- 2 (BLOCKS * 8192/1024/1024)-
- 3 (Num_rows * avg_row_len/1024/1024) "Data lower than HWM in MB"
- 4 from User_tables
- 5 WHERE table_name = ' T1 ';
- TABLE_NAME Data lower than HWM in MB
- -------------------- -------------------------
- T1 5.07086182
Three: View execution plan, full table scan probably consumes CPU 1175
- SQL> Explain plan for select * from T1;
- has been explained.
- SQL> select * from table (dbms_xplan.display);
- Plan_table_output
- --------------------------------------------------------------------------------
- Plan Hash value:3617692013
- --------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
- --------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 299k| 28m| 1175 (1) | 00:00:15 |
- | 1 | TABLE ACCESS full| T1 | 299k| 28m| 1175 (1) | 00:00:15 |
- --------------------------------------------------------------------------
Four: Delete Most of the data, collect statistics, full table scan still need to consume CPU 1168
- SQL> Delete from t1 where object_id>100;
- 298852 rows have been deleted.
- SQL> commit;
- Submit complete.
- SQL> select COUNT (*) from T1;
- COUNT (*)
- ----------
- 396
- SQL> Exec dbms_stats.gather_table_stats (' HR ', ' T1 ',cascade=>true);
- The PL/SQL process has completed successfully.
- SQL> Analyze table T1 compute statistics;
- Table has been analyzed.
- SQL> SELECT blocks, Empty_blocks, num_rows from user_tables WHERE table_name =' T1 ';
- BLOCKS Empty_blocks Num_rows
- ---------- ------------ ----------
- 4302 50 396
- SQL> Explain plan for select * from T1;
- has been explained.
- SQL> select * from table (dbms_xplan.display);
- Plan_table_output
- ------------------------------------------------------------------------------
- Plan Hash value:3617692013
- --------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
- --------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 396 | 29700 | 1168 (1) | 00:00:15 |
- | 1 | TABLE ACCESS full| T1 | 396 | 29700 | 1168 (1) | 00:00:15 |
- --------------------------------------------------------------------------
Five: Estimate how much space is not available under the high watermark, but it also needs to be hard-working data for full-table scanning
- SQL> SELECT table_name,
- 2 (BLOCKS * 8192/1024/1024)-
- 3 (Num_rows * avg_row_len/1024/1024) "Data lower than HWM in MB"
- 4 from User_tables
- 5 WHERE table_name = ' T1 ';
- TABLE_NAME Data lower than HWM in MB
- -------------------- -------------------------
- T1 33.5791626
VI: Defragment the table and collect statistics again
- SQL> ALTER TABLE T1 enable row movement;
- The table has changed.
- SQL> ALTER TABLE T1 shrink space cascade;
- The table has changed.
- SQL> select sum (bytes)/1024/1024 from dba_segments where segment_name=' T1 ';
- SUM (BYTES)/1024/1024
- --------------------
- .125
- SQL> select sum (bytes)/1024/1024 from dba_segments where segment_name= ' idx_t1_id
- ‘;
- SUM (BYTES)/1024/1024
- --------------------
- .0625
- SQL> SELECT table_name,
- 2 (BLOCKS * 8192/1024/1024)-
- 3 (Num_rows * avg_row_len/1024/1024) "Data lower than HWM in MB"
- 4 from User_tables
- 5 WHERE table_name = ' T1 ';
- TABLE_NAME Data lower than HWM in MB
- -------------------- -------------------------
- T1 33.5791626
- SQL> Exec dbms_stats.gather_table_stats (' HR ', ' T1 ',cascade=>true);
- The PL/SQL process has completed successfully.
- At this time, only 0.1M of useless work, the execution plan, full table scan also only need to consume CPU 3
- SQL> SELECT table_name,
- 2 (BLOCKS * 8192/1024/1024)-
- 3 (Num_rows * avg_row_len/1024/1024) "Data lower than HWM in MB"
- 4 from User_tables
- 5 WHERE table_name = ' T1 ';
- TABLE_NAME Data lower than HWM in MB
- -------------------- -------------------------
- T1.010738373
- SQL> select * from table (dbms_xplan.display);
- Plan_table_output
- --------------------------------------------------------------------------------
- Plan Hash value:3617692013
- --------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
- --------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 396 | 29700 | 3 (0) | 00:00:01 |
- | 1 | TABLE ACCESS full| T1 | 396 | 29700 | 3 (0) | 00:00:01 |
- --------------------------------------------------------------------------
- A total of only 5 blocks, there are 50 empty blocks, obviously empty_blocks information expires
- SQL> select blocks,empty_blocks,num_rows from User_tables where table_name=' T1 ';
- BLOCKS Empty_blocks Num_rows
- ---------- ------------ ----------
- 5 50 396
- SQL> Analyze table T1 compute statistics;
- Table has been analyzed.
- SQL> select blocks,empty_blocks,num_rows from User_tables where table_name=' T1 ';
- BLOCKS Empty_blocks Num_rows
- ---------- ------------ ----------
- 5 3 396
Reference: http://surachartopun.com/2011/08/determine-hwm-and-reduce-it-by-shrink.html
For information on how to determine which tables need to be defragmented, you can use the scripts in the attachments to query them, please refer to: http://www.toadworld.com/KNOWLEDGE/KnowledgeXpertforOracle/tabid/648/ Topicid/otnn18/default.aspx
About Oracle Table defragmentation