关于Oracle表碎片整理

数据库在日常使用过程中,不断的insert,delete,update操作,导致表和索引出现碎片是在所难免的事情,碎片多了,sql的执行效率自然就差了,道理很简单,高水位线(HWL)下的许多数据块都是无数据的,但全表扫描的时候要扫描到高水位线的数据块,也就是说oracle要做许多的无用功!因此oracle提供了shrink space碎片整理功能。对于索引,可以采取rebuild online的方式进行碎片整理,一般来说,经常进行DML操作的对象DBA要定期进行维护,同时注意要及时更新统计信息!

一:准备测试数据,使用HR用户,创建T1表,插入约30W的数据,并根据object_id创建普通索引,表占存储空间34M左右,索引占6M左右的存储空间

  1. SQL> conn /as sysdba
  2. 已连接。
  3. SQL> select default_tablespace from dba_users where username=‘HR‘;
  4. DEFAULT_TABLESPACE
  5. ------------------------------------------------------------
  6. USERS
  7. SQL> conn hr/hr
  8. 已连接。
  9. SQL> insert into t1 select * from t1;
  10. 已创建 74812 行。
  11. SQL> insert into t1 select * from t1;
  12. 已创建 149624 行。
  13. SQL> commit;
  14. 提交完成。
  15. SQL> create index idx_t1_id on t1(object_id);
  16. 索引已创建。
  17. SQL> exec dbms_stats.gather_table_stats(‘HR‘,‘T1‘,CASCADE=>TRUE);
  18. PL/SQL 过程已成功完成。
  19. SQL> select count(1) from t1;
  20. COUNT(1)
  21. ----------
  22. 299248
  23. SQL> select sum(bytes)/1024/1024 from dba_segments where segment_name=‘T1‘;
  24. SUM(BYTES)/1024/1024
  25. --------------------
  26. 34.0625
  27. SQL> select sum(bytes)/1024/1024 from dba_segments where segment_name=‘IDX_T1_ID‘;
  28. SUM(BYTES)/1024/1024
  29. --------------------
  30. 6

二:估算表在高水位线下还有多少空间可用,这个值应当越低越好,表使用率越接近高水位线,全表扫描所做的无用功也就越少!

DBMS_STATS包无法获取EMPTY_BLOCKS统计信息,所以需要用analyze命令再收集一次统计信息

  1. SQL> SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name =‘T1‘;
  2. BLOCKS EMPTY_BLOCKS   NUM_ROWS
  3. ---------- ------------ ----------
  4. 4302            0     299248
  5. SQL> analyze table t1 compute statistics;
  6. 表已分析。
  7. SQL> SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name =‘T1‘;
  8. BLOCKS EMPTY_BLOCKS   NUM_ROWS
  9. ---------- ------------ ----------
  10. 4302           50     299248
  11. SQL> col table_name for a20
  12. SQL> SELECT TABLE_NAME,
  13. 2         (BLOCKS * 8192 / 1024 / 1024) -
  14. 3         (NUM_ROWS * AVG_ROW_LEN / 1024 / 1024) "Data lower than HWM in MB"
  15. 4    FROM USER_TABLES
  16. 5   WHERE table_name = ‘T1‘;
  17. TABLE_NAME           Data lower than HWM in MB
  18. -------------------- -------------------------
  19. T1                                  5.07086182

三: 查看执行计划,全表扫描大概需要消耗CPU 1175

  1. SQL> explain plan for select * from t1;
  2. 已解释。
  3. SQL> select * from table(dbms_xplan.display);
  4. PLAN_TABLE_OUTPUT
  5. --------------------------------------------------------------------------------
  6. Plan hash value: 3617692013
  7. --------------------------------------------------------------------------
  8. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  9. --------------------------------------------------------------------------
  10. |   0 | SELECT STATEMENT  |      |   299K|    28M|  1175   (1)| 00:00:15 |
  11. |   1 |  TABLE ACCESS FULL| T1   |   299K|    28M|  1175   (1)| 00:00:15 |
  12. --------------------------------------------------------------------------

四:删除大部分数据,收集统计信息,全表扫描依然需要消耗CPU 1168

  1. SQL> delete from t1 where object_id>100;
  2. 已删除298852行。
  3. SQL> commit;
  4. 提交完成。
  5. SQL> select count(*) from t1;
  6. COUNT(*)
  7. ----------
  8. 396
  9. SQL>  exec dbms_stats.gather_table_stats(‘HR‘,‘T1‘,CASCADE=>TRUE);
  10. PL/SQL 过程已成功完成。
  11. SQL> analyze table t1 compute statistics;
  12. 表已分析。
  13. SQL> SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name =‘T1‘;
  14. BLOCKS EMPTY_BLOCKS   NUM_ROWS
  15. ---------- ------------ ----------
  16. 4302           50        396
  17. SQL> explain plan for select * from t1;
  18. 已解释。
  19. SQL> select * from table(dbms_xplan.display);
  20. PLAN_TABLE_OUTPUT
  21. ------------------------------------------------------------------------------
  22. Plan hash value: 3617692013
  23. --------------------------------------------------------------------------
  24. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  25. --------------------------------------------------------------------------
  26. |   0 | SELECT STATEMENT  |      |   396 | 29700 |  1168   (1)| 00:00:15 |
  27. |   1 |  TABLE ACCESS FULL| T1   |   396 | 29700 |  1168   (1)| 00:00:15 |
  28. --------------------------------------------------------------------------

五:估算表在高水位线下还有多少空间是无数据的,但在全表扫描时又需要做无用功的数据

  1. SQL> SELECT TABLE_NAME,
  2. 2         (BLOCKS * 8192 / 1024 / 1024) -
  3. 3         (NUM_ROWS * AVG_ROW_LEN / 1024 / 1024) "Data lower than HWM in MB"
  4. 4    FROM USER_TABLES
  5. 5   WHERE table_name = ‘T1‘;
  6. TABLE_NAME           Data lower than HWM in MB
  7. -------------------- -------------------------
  8. T1                                  33.5791626

六:对表进行碎片整理,重新收集统计信息

  1. SQL> alter table t1 enable row movement;
  2. 表已更改。
  3. SQL> alter table t1 shrink space cascade;
  4. 表已更改。
  5. SQL> select sum(bytes)/1024/1024 from dba_segments where segment_name=‘T1‘;
  6. SUM(BYTES)/1024/1024
  7. --------------------
  8. .125
  9. SQL> select sum(bytes)/1024/1024 from dba_segments where segment_name=‘IDX_T1_ID
  10. ‘;
  11. SUM(BYTES)/1024/1024
  12. --------------------
  13. .0625
  14. SQL> SELECT TABLE_NAME,
  15. 2         (BLOCKS * 8192 / 1024 / 1024) -
  16. 3         (NUM_ROWS * AVG_ROW_LEN / 1024 / 1024) "Data lower than HWM in MB"
  17. 4    FROM USER_TABLES
  18. 5   WHERE table_name = ‘T1‘;
  19. TABLE_NAME           Data lower than HWM in MB
  20. -------------------- -------------------------
  21. T1                                  33.5791626
  22. SQL> exec dbms_stats.gather_table_stats(‘HR‘,‘T1‘,CASCADE=>TRUE);
  23. PL/SQL 过程已成功完成。
  24. 这个时候,只剩下0.1M的无用功了,执行计划中,全表扫描也只需要消耗CPU 3
  25. SQL> SELECT TABLE_NAME,
  26. 2         (BLOCKS * 8192 / 1024 / 1024) -
  27. 3         (NUM_ROWS * AVG_ROW_LEN / 1024 / 1024) "Data lower than HWM in MB"
  28. 4    FROM USER_TABLES
  29. 5   WHERE table_name = ‘T1‘;
  30. TABLE_NAME           Data lower than HWM in MB
  31. -------------------- -------------------------
  32. T1                                  .010738373
  33. SQL> select * from table(dbms_xplan.display);
  34. PLAN_TABLE_OUTPUT
  35. --------------------------------------------------------------------------------
  36. Plan hash value: 3617692013
  37. --------------------------------------------------------------------------
  38. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
  39. --------------------------------------------------------------------------
  40. |   0 | SELECT STATEMENT  |      |   396 | 29700 |     3   (0)| 00:00:01 |
  41. |   1 |  TABLE ACCESS FULL| T1   |   396 | 29700 |     3   (0)| 00:00:01 |
  42. --------------------------------------------------------------------------
  43. 总共只有5个块,空块却有50个,明显empty_blocks信息过期
  44. SQL> select blocks,empty_blocks,num_rows from user_tables where table_name=‘T1‘;
  45. BLOCKS EMPTY_BLOCKS   NUM_ROWS
  46. ---------- ------------ ----------
  47. 5           50        396
  48. SQL> analyze table t1 compute statistics;
  49. 表已分析。
  50. SQL> select blocks,empty_blocks,num_rows from user_tables where table_name=‘T1‘;
  51. BLOCKS EMPTY_BLOCKS   NUM_ROWS
  52. ---------- ------------ ----------
  53. 5            3        396

参考:http://surachartopun.com/2011/08/determine-hwm-and-reduce-it-by-shrink.html

关于如何确定哪些表需要进行碎片整理,可以使用附件中的脚本去查询,具体请参考:http://www.toadworld.com/KNOWLEDGE/KnowledgeXpertforOracle/tabid/648/TopicID/OTNN18/Default.aspx

时间: 2024-10-03 14:03:13

关于Oracle表碎片整理的相关文章

MySQL数据表碎片整理

在MySQL中,我们经常会使用VARCHAR.TEXT.BLOB等可变长度的文本数据类型.不过,当我们使用这些数据类型之后,我们就不得不做一些额外的工作--MySQL数据表碎片整理. 那么,为什么在使用这些数据类型之后,我们就要对MySQL定期进行碎片整理呢? 现在,我们先来看一个具体的例子.在这里,我们使用如下SQL语句在MySQL自带的TEST数据库中创建名为DEMO的数据表并插入5条测试数据. --创建DEMO表  id int unsigned,  body text  ) engine

MySQL关于表碎片整理OPTIMIZE TABLE操作

MySQL关于表碎片整理OPTIMIZE TABLE操作的官方建议1.MySQL官方建议不要经常(每小时或每天)进行碎片整理,一般根据实际情况,只需要每周或者每月整理一次即可,可以写成定时任务来做.2.OPTIMIZE TABLE只对MyISAM,BDB和InnoDB表起作用,尤其是MyISAM表的作用最为明显.此外,并不是所有表都需要进行碎片整理,一般只需要对包含上述可变长度的文本数据类型的表进行整理即可.3.在OPTIMIZE TABLE运行过程中,MySQL会锁定表.4.默认情况下,直接对

Mysql Innodb 表碎片整理

一.为什么会产生碎片 简单的说,删除数据必然会在数据文件中造成不连续的空白空间,而当插入数据时,这些空白空间则会被利用起来.于是造成了数据的存储位置不连续,以及物理存储顺序与理论上的排序顺序不同,这种是数据碎片.实际上数据碎片分为两种,一种是单行数据碎片,另一种是多行数据碎片.前者的意思就是一行数据,被分成N个片段,存储在N个位置.后者的就是多行数据并未按照逻辑上的顺序排列.当有大量的删除和插入操作时,必然会产生很多未使用的空白空间,这些空间就是多出来的额外空间.索引也是文件数据,所以也会产生索

oracle 数据库碎片化管理

******************************************************************************** 1.表空间碎片 ******************************************************************************** ----1.查看fsfi值 select a.tablespace_name, trunc(sqrt(max(blocks)/sum(blocks))* (10

mysql表碎片的查询自己回收

在MySQL中,我们经常会使用VARCHAR.TEXT.BLOB等可变长度的文本数据类型.不过,当我们使用这些数据类型之后,我们就不得不做一些额外的工作--MySQL数据表碎片整理. 每当MySQL从你的列表中删除了一行内容,该段空间就会被留空.而在一段时间内的大量删除操作,会使这种留空的空间变得比存储列表内容所使用的空间更大. 当MySQL对数据进行扫描时,它扫描的对象实际是列表的容量需求上限,也就是数据被写入的区域中处于峰值位置的部分.如果进行新的插入操作,MySQL将尝试利用这些留空的区域

Oracle 数据库整理表碎片

Oracle 数据库整理表碎片 转载:http://kyle.xlau.org/posts/table-fragmentation.html 表碎片的来源 当针对一个表的删除操作很多时,表会产生大量碎片.删除操作释放的空间不会被插入操作立即重用,甚至永远也不会被重用. 怎样确定是否有表碎片 -- 收集表统计信息 SQL> exec dbms_stats.gather_table_stats(ownname=>'SCHEMA_NAME',tabname=> 'TABLE_NAME'); -

oracle表和对象基础维护笔记

一 oracle表和对象基础维护笔记 1.1 常见概念 1.2 创建表 1.3 表常见字段 1.4 增加或删除字段 1.5 更新字段 1.6 重命名表 1.7 改变表存储表空间和存储参数 1.8 删除表 1.9 表注释 1.10 分区表的管理 1.11 常用数据字典 二 约束 2.1 非空约束 2.2 主键约束 2.3 唯一性约束 2.4 外键约束 2.5 约束管理 三 索引 3.2 创建索引 3.3 改变索引存储参数 3.4 重建索引 3.5 索引碎片整理 3.6 删除索引 3.7 数据字典

sql索引碎片产生的原理 解决碎片的办法(sql碎片整理)

本文讲述了SQL SERVER中碎片产生的原理,内部碎片和外部碎片的概念.以及解决碎片的办法和填充因子.在数据库中,往往每一个对于某一方面性能增加的功能也会伴随着另一方面性能的减弱.系统的学习数据库知识,从而根据具体情况进行权衡,是dba和开发人员的必修课 本文需要你对索引和SQL中数据的存储方式有一定了解 在SQL Server中,存储数据的最小单位是页,每一页所能容纳的数据为8060字节.而页的组织方式是通过B树结构(表上没有聚集索引则为堆结构,不在本文讨论之列)如下图: 在聚集索引B树中,

小知识-为什么Linux不需要磁盘碎片整理

转载至:http://beikeit.com/post-495.html 简单译文: 这段linux官方资料主要介绍了外部碎片(external fragmentation).内部碎片(internal fragmentation)的概念及相关情况,说明了linux文件系统在磁盘还有5%空闲空间的情况下是不需要碎片整理的.(Linux native file systems do not need defragmentation under normal use and this include