--Oracle 高水位线和全表扫描
--------------------------2013/11/22 高水位线好比水库中储水的水位线,用于描述数据库中段的扩展方式。高水位线对全表扫描方式有着至关重要的影响。当使用delete 操作
表记录时,高水位线并不会下降,随之导致的是全表扫描的实际开销并没有任何减少。本文给出高水位线的描述,如何降低高水位线,以及高水
位线对全表扫描的影响。
一、何谓高水位线
如前所述,类似于水库中储水的水位线。只不过在数据库中用于描述段的扩展方式。
可以将数据段或索引段等想象为一个从左到右依次排开的一系列块。当这些块中未填充任何数据时,高水位线位于块的最左端(底端)
随着记录的不断增加,新块不断地被填充并使用,高水位线随之向右移动。高水位线之上为未格式化的数据块。
删除(delete)操作之后,高水位线之下的块处于空闲状态,但高水位线并不随之下降,直到重建,截断或收缩表段。
全表扫描会扫描高水位线之下的所有块,包括空闲数据块(执行了delete操作)。
低高水位线
是在使用ASSM时的一个概念。即使用ASSM时除了高水位线之外,还包括一个低高水位线。低高水位线一定是位于高水位线之下。
当段使用MSSM管理方式时只有一种情况即只存在一个高水位线。
使用MMSM时,当HWM升高时,Oracle立即格式化所有块且有效,并可以安全读取。仅当第一次使用时完成格式化,便于安全读取数据。
使用ASSM时,当HWM升高时,Oracle并不会立即格式化所有块。仅当第一次使用时完成格式化,便于安全读取数据。
使用低高水位线可以减少当全面扫描表段时,低高水位线与高水位线之间不安全块的检查数量。即低高水位线之下的块不再检查。
二、演示高水位线与全表扫描
SQL> create table t    -->创建测试表
  2  as
  3  select rownum as id,
  4  round(dbms_random.normal*1000) AS val1,
  5  dbms_random.string('p',250) AS pad
  6  from dual
  7  connect by level <=10000;
Table created.
SQL> exec dbms_stats.gather_table_stats('SCOTT','T',cascade=>true);  -->收集统计信息
SQL> @Tab_Stat                        -->从dba_tab_statistics中获得表对象的统计信息,此时无empty_blocks的信息
Enter value for input_table_name: t
Enter value for input_owner: scott
  NUM_ROWS      BLKS    EM_BLKS  AVG_SPACE  CHAIN_CNT AVG_ROW_LEN AVG_ROWS_PER_BLOCK LST_ANLY  STA
---------- ---------- ---------- ---------- ---------- ----------- ------------------ --------- ---
    10000        387          0          0          0        259                26 03-NOV-11 NO
/**************************************************/
/* Author: Robinson Cheng                        */ 
/* Blog:  http://blog.csdn.net/robinson_0612    */
/* MSN:    robinson_0612@hotmail.com              */
/* QQ:    645746311                              */ 
/**************************************************/
SQL> analyze table t compute statistics;    -->执行analyze
SQL> @Tab_Stat                              -->此时的empty_blocks值为125
Enter value for input_table_name: t
Enter value for input_owner: scott
  NUM_ROWS      BLKS    EM_BLKS  AVG_SPACE  CHAIN_CNT AVG_ROW_LEN AVG_ROWS_PER_BLOCK LST_ANLY  STA
---------- ---------- ---------- ---------- ---------- ----------- ------------------ --------- ---
    10000        387        125        920          0        262                26 03-NOV-11 NO
SQL> col segment_name format a15
SQL> select segment_name,segment_type,blocks,extents from dba_segments  -->查看表段上的块的信息
  2  where segment_name='T' and owner='SCOTT';
SEGMENT_NAME    SEGMENT_TYPE          BLOCKS    EXTENTS            -->此数据字典中记录的块数为512块(包含了已使用块与空闲块)
--------------- ------------------ ---------- ----------
T              TABLE                    512        19
SQL> set autotrace traceonly;    -->开启autotrace
SQL> select count(*) from t;    -->此时SQL语句的执行计划为全表扫描(执行计划中部分信息被省略)
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
-------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Cost (%CPU)| Time    |
-------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |    86  (0)| 00:00:02 |
|  1 |  SORT AGGREGATE    |      |    1 |            |          |
|  2 |  TABLE ACCESS FULL| T    | 10000 |    86  (0)| 00:00:02 |
-------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        375  consistent gets          -->consistent gets的值为375
          0  physical reads
SQL> set autotrace off;
SQL> delete from t where rownum<=9900;  -->删除大多数的记录,删除后剩余记录值为100
9900 rows deleted.
SQL> commit;
SQL> exec dbms_stats.gather_table_stats('SCOTT','T',cascade=>true); -->收集统计信息
SQL> analyze table t compute statistics;  -->收集统计信息
SQL> @Tab_Stat                          -->此时对象上的统计信息无任何变化,即高水位线没有发生任何变化
Enter value for input_table_name: t
Enter value for input_owner: scott
  NUM_ROWS      BLKS    EM_BLKS  AVG_SPACE  CHAIN_CNT AVG_ROW_LEN AVG_ROWS_PER_BLOCK LST_ANLY  STA
---------- ---------- ---------- ---------- ---------- ----------- ------------------ --------- ---
      100        387        125      7921          0        262                  0 03-NOV-11 NO
                
SQL> set autotrace traceonly    
SQL> select count(*) from t;    -->SQL的执行计划中预估的值准确,为100行
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
-------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Cost (%CPU)| Time    |
-------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |    86  (0)| 00:00:02 |
|  1 |  SORT AGGREGATE    |      |    1 |            |          |
|  2 |  TABLE ACCESS FULL| T    |  100 |    86  (0)| 00:00:02 |
-------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        375  consistent gets  -->consistent gets的值仍然为375,并没有下降
          0  physical reads
SQL> set autotrace off;
SQL> alter table t enable row movement;      -->启用row movement
SQL> alter table t shrink space cascade;    --> 实施shrink space
SQL> alter table t disable row movement;
SQL> exec dbms_stats.gather_table_stats('SCOTT','T');
SQL> analyze table t compute statistics;
SQL> @Tab_Stat                          -->此时对象上的统计信息已发生变化,已使用的块为4块,空闲块为4块
Enter value for input_table_name: t
Enter value for input_owner: scott
  NUM_ROWS      BLKS    EM_BLKS  AVG_SPACE  CHAIN_CNT AVG_ROW_LEN AVG_ROWS_PER_BLOCK LST_ANLY  STA
---------- ---------- ---------- ---------- ---------- ----------- ------------------ --------- ---
      100          4          4      7921          0        259                25 03-NOV-11 NO
SQL> set autotrace traceonly 
SQL> select count(*) from t;
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
-------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Cost (%CPU)| Time    |
-------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |    3  (0)| 00:00:01 |
|  1 |  SORT AGGREGATE    |      |    1 |            |          |
|  2 |  TABLE ACCESS FULL| T    |  100 |    3  (0)| 00:00:01 |
-------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          6  consistent gets    -->表段收缩之后,consistent gets由375下降为6
          0  physical reads
                
SQL> truncate table t;  -->使用表截断技术(turncate table)
Table truncated.
SQL> exec dbms_stats.gather_table_stats('SCOTT','T');  -->收集统计信息
PL/SQL procedure successfully completed.
SQL> select count(*) from t;  -->此时执行计划中的rows变为1
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
-------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Cost (%CPU)| Time    |
-------------------------------------------------------------------
|  0 | SELECT STATEMENT  |      |    1 |    2  (0)| 00:00:01 |
|  1 |  SORT AGGREGATE    |      |    1 |            |          |
|  2 |  TABLE ACCESS FULL| T    |    1 |    2  (0)| 00:00:01 |
-------------------------------------------------------------------
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          3  consistent gets  -->consistent gets的值降为3
          0  physical reads
三、总结
1、高水线直接决定了全表扫描所需要的I/O开销
2、delete操作不会降低高水位线,高水位线之下的所有块依然被扫描
3、使用truncate 会重置高水位线到0位
4、定期使用alter table tab_name shrink space cascade 有效减少该对象上的I/O开销

Oracle 高水位线和全表扫描的更多相关文章

  1. oracle优化:避免全表扫描(高水位线)

    如果我们查询了一条SQL语句,这条SQL语句进行了全表扫描,那到底是扫描了多少个数据块呢?是表有多少数据,就扫描多少块吗?不是的.而是扫描高水位线一下的所有块.有的时候有人经常说,我的表也不大呀,怎么 ...

  2. oracle优化:避免全表扫描

    http://blog.csdn.net/onetree2010/article/details/6098259

  3. Oracle列操作引起的全表扫描

    首先是一种比较明显的情况: select * from table where column + 1 = 2 这里对column进行了列操作,加1以后,与column索引里的内容对不上,导致colum ...

  4. Oracle 表的访问方式(1) ---全表扫描、通过ROWID访问表

    1.Oracle访问表的方式 全表扫描.通过ROWID访问表.索引扫描 2.全表扫描(Full Table Scans, FTS) 为实现全表扫描,Oracle顺序地访问表中每条记录,并检查每一条记录 ...

  5. Oracle全表扫描

    优化器在形成执行计划时需要做的一个重要选择——如何从数据库查询出需要的数据.对于SQL语句存取的任何表中的任何行,可能存在许多存取路径(存取方法),通过它们可以定位和查询出需要的数据.优化器选择其中自 ...

  6. Oracle 11g全表扫描以Direct Path Read方式执行

    在Oracle Database 11g中有一个新特性,全表扫描可以通过直接路径读的方式来执行(Direct Path Read),这是一个合理的变化,如果全表扫描的大量数据读取是偶发性的,则直接路径 ...

  7. Oracle的大表,小表与全表扫描

    大小表区分按照数据量的大小区分: 通常对于小表,Oracle建议通过全表扫描进行数据访问,对于大表则应该通过索引以加快数据查询,当然如果查询要求返回表中大部分或者全部数据,那么全表扫描可能仍然是最好的 ...

  8. Oracle收集对表收集统计信息导致全表扫描直接路径读?

    direct path read深入解析 前言 最近碰到一件很奇葩的事情,因为某条SQL执行缓慢,原因是走了笛卡尔(两组大数据结果集),而且笛卡尔还是NL的一个部分,要循环31M次. 很容易发现是统计 ...

  9. (转) Oracle SQL优化必要的全表扫描思路分析

    大多数情况下,我们需要避免SQL在查询时进行全表扫描(FTS),但是对于必须需要进行全表扫描的情况,也可以进行一些优化处理. 即使全表扫描是检索所需数据的唯一可行方法,仍然有多种方法来提升查询性能.优 ...

随机推荐

  1. 什么是Hadoop

    配上官方介绍 What Is Apache Hadoop?    The Apache™ Hadoop® project develops open-source software for relia ...

  2. JAVA - 工厂模式

    1. 简单工厂违背OCP(Open Close Principle)原则 , 即对增加开放,对修改关闭.如果要符合OCP原则,要针对接口编程. //简单工厂模式,违反了OCP原则 public cla ...

  3. java 中的常用类

    Java 中的包装类 相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等. 基本数据类型是不具备对象的特性的,比如基本类型不能调用方法.功能 ...

  4. shell十分钟教程

    1.先介绍下shell的工作原理 Shell可以被称作是脚本语言,因为它本身是不需要编译的,而是通过解释器解释之后再编译执行,和传统语言相比多了解释的过程所以效率会略差于传统的直接编译的语言. 但是s ...

  5. Unreal Engine 4(虚幻UE4)GameplayAbilities 插件入门教程(四)技能屏蔽和简单的Buff等

    本节内容继续上一节教程的内容(如果没有看过前面的教程,请前往学习),不会讲太难的新东西,而是继续探究技能标签(Abiilty Tags)的内容.先来一道开胃菜. 第1.1步: 将上一次的召唤冰龙中的C ...

  6. php之试触法----error--关键字的误用

    实际开发中,在不同网页的输出中,常常有许多公共的代码或者变量需要使用,于是定义了以下类来缩减代码量 如下代码所示: <?php class universalClass { function w ...

  7. java volatitle介绍与使用

    关于关键字volatile可以说是Java虚拟机提供的轻量级的同步机制,但是它并不容易完全被正常.完整地理解,以至于许多程序员都不习惯去使用它,遇到需要处理多线程数据竞争问题的时候一律使用Synchr ...

  8. AppDomain 及BuildManager

    一.AppDomain.CurrentDomain.DynamicDirectory 只有在Web项目中在值,动态执行目录像下面这样 Framework\v4.0.30319\Temporary AS ...

  9. 关于delete使用limit的一些注意事项

    在使用delete删除记录时,如果表里面存在多条相同的记录,但是此刻你只想删除一条记录,那么limit就派上了用场.但是使用limit的时候得注意: 如图,您如果想着删除第一个名字叫做张三的,如果你这 ...

  10. Linux常用命令及shell技巧

    这里列出一些个人在工作中常使用的各种linux命令,每一个不详细讲参数,只写经常用的参数.希望快速获得在linux命令行工作的能力的朋友可以看看.本人一直觉的,不使用linux 图形界面,以xshel ...