Oracle 基础篇 --- 重建B树索引对性能的影响

#####重建B树索引缓存

######1. 如何重建B树索引oracle

重建索引有两种方法:ide

  • 一种是最简单的,删除原索引,而后重建;
  • 第二种是使用ALTER INDEX … REBUILD;

命令对索引进行重建。第二种方式是从oracle 7.3.3版本开始引入的,从而使得用户在重建索引时没必要删除原索引再从新CREATE INDEX了。ALTER INDEX … REBUILD相对CREATE INDEX有如下好处:函数

1) 它使用原索引的叶子节点做为新索引的数据来源。咱们知道,原索引的叶子节点的数据块一般都要比表里的数据块要少不少,所以进行的I/O就会减小;同时,因为原索引的叶子节点里的索引条目已经排序了,所以在重建索引的过程当中,所作的排序工做也要少的多。oop

2) 自从oracle 8.1.6以来,ALTER INDEX … REBUILD命令能够添加ONLINE短语。这使得在重建索引的过程当中,用户能够继续对原来的索引进行修改,也就是说能够继续对表进行DML操做。性能


而同时,ALTER INDEX … REBUILD与CREATE INDEX也有不少相同之处:测试

1) 它们均可以经过添加PARALLEL提示进行并行处理。ui

2) 它们均可以经过添加NOLOGGING短语,使得重建索引的过程当中产生最少的重作条目(redo entry)。code

3) 自从oracle 8.1.5以来,它们均可以田间COMPUTE STATISTICS短语,从而在重建索引的过程当中,就生成CBO所须要的统计信息,这样就避免了索引建立完毕之后再次运行analyze或dbms_stats来收集统计信息。orm


当咱们重建索引之后,在物理上所能得到的好处就是可以减小索引所占的空间大小(特别是可以减小叶子节点的数量)。而索引大小减少之后,又能带来如下若干好处:

1) CBO对于索引的使用可能会产生一个较小的成本值,从而在执行计划中选择使用索引。

2) 使用索引扫描的查询扫描的物理索引块会减小,从而提升效率。

3) 因为须要缓存的索引块减小了,从而让出了内存以供其余组件使用。


尽管重建索引具备必定的好处,可是盲目的认为重建索引可以解决不少问题也是不正确的。好比我见过一个生产系统,每隔一个月就要重建全部的索引(并且我相信,不少生产系统可能都会这么作),其中包括一些100GB的大表。为了完成重建全部的索引,每每须要把这些工做分散到多个晚上进行。事实上,这是一个7×24的系统,仅重建索引一项任务就消耗了很是多的系统资源。可是每隔一段时间就重建索引有意义吗?这里就有一些关于重建索引的很流行的说法,主要包括:

1) 若是索引的层级超过X(X一般是3)级之后须要经过重建索引来下降其级别。

2) 若是常常删除索引键值,则须要定时重建索引来收回这些被删除的空间。

3) 若是索引的clustering_factor很高,则须要重建索引来下降该值。

4) 按期重建索引可以提升性能。

对于第一点来讲,咱们在前面已经知道,B树索引是一棵在高度上平衡的树,因此重建索引基本不可能下降其级别,除非是极特殊的状况致使该索引有很是大量的碎片,致使B树索引“虚高”,那么这实际又来到第二点上(由于碎片一般都是因为删除引发的)。实际上,对于第一和第二点,咱们应该经过运行ALTER INDEX … REBUILD命令之后检查index_stats.pct_used字段来判断是否有必要重建索引。

SQL> analyze index emp3_name_ix validate structure;

Index analyzed.

SQL> select LF_ROWS, LF_ROWS_LEN,DEL_LF_ROWS,DEL_LF_ROWS_LEN, USED_SPACE, BTREE_SPACE from index_stats;

   LF_ROWS LF_ROWS_LEN DEL_LF_ROWS DEL_LF_ROWS_LEN USED_SPACE BTREE_SPACE
---------- ----------- ----------- --------------- ---------- -----------
    110002     2053033       10000          150000    2065045     6324964

SQL> alter index emp3_name_ix rebuild;

Index altered.

SQL> analyze index emp3_name_ix validate structure;

Index analyzed.

SQL> select LF_ROWS, LF_ROWS_LEN,DEL_LF_ROWS,DEL_LF_ROWS_LEN, USED_SPACE, BTREE_SPACE from index_stats;

   LF_ROWS LF_ROWS_LEN DEL_LF_ROWS DEL_LF_ROWS_LEN USED_SPACE BTREE_SPACE
---------- ----------- ----------- --------------- ---------- -----------
    100002     1903033           0               0    1906995     2134964

######2. 重建B树索引对于clustering_factor的影响

而对于clustering_factor来讲,它是用来比较索引的顺序程度与表的杂乱排序程度的一个度量。Oracle在计算某个clustering_factor时,会对每一个索引键值查找对应到表的数据,在查找的过程当中,会跟踪从一个表的数据块跳转到另一个数据块的次数(固然,它不可能真的这么作,源代码里只是简单的扫描索引,从而得到ROWID,而后从这些ROWID得到表的数据块的地址)。每一次跳转时,有个计数器就会增长,最终该计数器的值就是clustering_factor。下图四描述了这个原理。

此处输入图片的描述

在上图四中,咱们有一个表,该表有4个数据块,以及20条记录。在列N1上有一个索引,上图中的每一个小黑点就表示一个索引条目。列N1的值如图所示。而N1的索引的叶子节点包含的值为:A、B、C、D、E、F。若是oracle开始扫描索引的底部,叶子节点包含的第一个N1值为A,那么根据该值能够知道对应的ROWID位于第一个数据块的第三行里,因此咱们的计数器增长1。同时,A值还对应第二个数据块的第四行,因为跳转到了不一样的数据块上,因此计数器再加1。一样的,在处理B时,能够知道对应第一个数据块的第二行,因为咱们从第二个数据块跳转到了第一个数据块,因此计数器再加1。同时,B值还对应了第一个数据块的第五行,因为咱们这里没有发生跳转,因此计数器不用加1。

在上面的图里,在表的每一行的下面都放了一个数字,它用来显示计数器跳转到该行时对应的值。当咱们处理完索引的最后一个值时,咱们在数据块上一共跳转了十次,因此该索引的clustering_factor为10。

注意第二个数据块,clustering_factor为8出现了4次。由于在索引里N1为E所对应的4个索引条目都指向了同一个数据块。从而使得clustering_factor再也不增加。一样的现象出如今第三个数据块中,它包含三条记录,它们的值都是C,对应的clustering_factor都是6。

从clustering_factor的计算方法上能够看出,咱们能够知道它的最小值就等于表所含有的数据块的数量;而最大值就是表所含有的记录的总行数。很明显,clustering_factor越小越好,越小说明经过索引查找表里的数据行时须要访问的表的数据块越少。


重建索引对于减少clustering_factor没有用处。

首先咱们建立一个测试表:

SQL> create table clustfact_test(id number, name varchar2(10));

Table created.

SQL> create index idx_clustfact_test on clustfact_test(id);

Index created.

SQL> begin
  2     for i in 1.. 100000 loop
  3       insert into clustfact_test values(mod(i,200), to_char(i));
  4  end loop;
  5  commit;
  6  end;
  7  /

PL/SQL procedure successfully completed.

SQL> exec dbms_stats.gather_table_stats(user,'clustfact_test',cascade=>true);

PL/SQL procedure successfully completed.

#由于使用了mod的关系,最终数据在表里排列的形式为:
0,1,2,3,4,5,…,197,198,199,0,1,2,3,…, 197,198,199,0,1,2,3,…, 197,198,199,0,1,2,3,…

SQL> select num_rows, blocks from user_tables where table_name = 'CLUSTFACT_TEST';

  NUM_ROWS     BLOCKS
---------- ----------
    100000        244

SQL> select num_rows, distinct_keys, AVG_LEAF_BLOCKS_PER_KEY, AVG_DATA_BLOCKS_PER_KEY, CLUSTERING_FACTOR from user_indexes where
  2  index_name = 'IDX_CLUSTFACT_TEST';

  NUM_ROWS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR
---------- ------------- ----------------------- ----------------------- -----------------
    100000           200                       1                     198             39683

#从上面的avg_data_blocks_per_key的值为198能够知道,每一个键值平均分布在198个数据块里,而整个表也就244个数据块。这也就是说,要获取某个键值的全部记录,几乎每次都须要访问全部的数据块。从这里已经能够猜想到clustering_factor会很是大。事实上,该值近4万,也说明该索引并不会颇有效。

SQL> select * from clustfact_test where id = 100;

500 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1230726760

------------------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                |   500 |  4500 |    69   (2)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| CLUSTFACT_TEST |   500 |  4500 |    69   (2)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("ID"=100)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        281  consistent gets
        244  physical reads
          0  redo size
      12114  bytes sent via SQL*Net to client
        887  bytes received via SQL*Net from client
         35  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        500  rows processed

#很明显,CBO弃用了索引,而使用了全表扫描。这实际上已经说明因为索引的clustering_factor太高,致使经过索引获取数据时跳转的数据块过多,成本太高,所以直接使用全表扫描的成本会更低。

#这时咱们来重建索引看看会对clustering_factor产生什么影响。从下面的测试中能够看到,没有任何影响。

SQL> alter index idx_clustfact_test rebuild;

Index altered.

SQL> select num_rows, distinct_keys, AVG_LEAF_BLOCKS_PER_KEY, AVG_DATA_BLOCKS_PER_KEY, CLUSTERING_FACTOR from user_indexes where
  2  index_name = 'IDX_CLUSTFACT_TEST';

  NUM_ROWS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR
---------- ------------- ----------------------- ----------------------- -----------------
    100000           200                       1                     198             39683

#那么当咱们将表里的数据按照id的顺序(也就是索引的排列顺序)重建时,该SQL语句会如何执行?

SQL> create table clustfact_test_temp as select * from clustfact_test order by id;

Table created.

SQL>  truncate table clustfact_test;

Table truncated.

SQL> insert into clustfact_test select * from clustfact_test_temp;

100000 rows created.

SQL> exec dbms_stats.gather_table_stats(user,'clustfact_test',cascade=>true);

PL/SQL procedure successfully completed.

SQL> select num_rows, distinct_keys, avg_leaf_blocks_per_key, avg_data_blocks_per_key,
  2  clustering_factor from user_indexes where index_name = 'IDX_CLUSTFACT_TEST';

  NUM_ROWS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR
---------- ------------- ----------------------- ----------------------- -----------------
    100000           200                       1                       1               244

SQL> set autotrace traceonly;
SQL> select * from clustfact_test where id = 100;

500 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 60478562

--------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                    |   451 |  4059 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| CLUSTFACT_TEST     |   451 |  4059 |     3   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_CLUSTFACT_TEST |   451 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID"=100)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         74  consistent gets
          0  physical reads
          0  redo size
      13715  bytes sent via SQL*Net to client
        887  bytes received via SQL*Net from client
         35  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        500  rows processed

因此咱们能够得出结论,若是仅仅是为了下降索引的clustering_factor而重建索引没有任何意义。下降clustering_factor的关键在于重建表里的数据。只有将表里的数据按照索引列排序之后,才能切实有效的下降clustering_factor。可是若是某个表存在多个索引的时候,须要仔细决定应该选择哪个索引列来重建表。


######2. 重建B树索引对于查询性能的影响

重建索引对于性能的提升到底会有什么做用。假设咱们有一个表,该表具备1百万条记录,占用了100000个数据块。而在该表上存在一个索引,在重建以前的pct_used为50%,高度为3,分支节点块数为40个,再加一个根节点块,叶子节点数为10000个;重建该索引之后,pct_used为90%,高度为3,分支节点块数降低到20个,再加一个根节点块,而叶子节点数降低到5000个。那么从理论上说:

  1. 若是经过索引获取单独1条记录来讲: 重建以前的成本:1个根+1个分支+1个叶子+1个表块=4个逻辑读 重建以后的成本:1个根+1个分支+1个叶子+1个表块=4个逻辑读 性能提升百分比:0
  1. 若是经过索引获取100条记录(占总记录数的0.01%)来讲,分两种状况: 最差的clustering_factor(即该值等于表的数据行数): 重建以前的成本:1个根+1个分支+0.000110000(1个叶子)+100个表块=103个逻辑读 重建以后的成本:1个根+1个分支+0.00015000(1个叶子)+100个表块=102.5个逻辑读 性能提升百分比:0.5%(也就是减小了0.5个逻辑读) 最好clustering_factor(即该值等于表的数据块): 重建以前的成本:1个根+1个分支+0.000110000(1个叶子)+0.0001100000(10个表块)=13个逻辑读 重建以后的成本:1个根+1个分支+0.00015000(1个叶子)+0.0001100000(10个表块)=12.5个逻辑读 性能提升百分比:3.8%(也就是减小了0.5个逻辑读)
  1. 若是经过索引获取10000条记录(占总记录数的1%)来讲,分两种状况: 最差的clustering_factor(即该值等于表的数据行数): 重建以前的成本:1个根+1个分支+0.0110000(100个叶子)+10000个表块=10102个逻辑读 重建以后的成本:1个根+1个分支+0.015000(50个叶子)+10000个表块=10052个逻辑读 性能提升百分比:0.5%(也就是减小了50个逻辑读) 最好clustering_factor(即该值等于表的数据块): 重建以前的成本:1个根+1个分支+0.0110000(100个叶子)+0.01100000(1000个表块)=1102个逻辑读 重建以后的成本:1个根+1个分支+0.015000(50个叶子)+0.01100000(1000个表块)=1052个逻辑读 性能提升百分比:4.5%(也就是减小了50个逻辑读)
  1. 若是经过索引获取100000条记录(占总记录数的10%)来讲,分两种状况: 最差的clustering_factor(即该值等于表的数据行数): 重建以前的成本:1个根+1个分支+0.110000(1000个叶子)+100000个表块=101002个逻辑读 重建以后的成本:1个根+1个分支+0.15000(500个叶子)+100000个表块=100502个逻辑读 性能提升百分比:0.5%(也就是减小了500个逻辑读) 最好clustering_factor(即该值等于表的数据块): 重建以前的成本:1个根+1个分支+0.110000(1000个叶子)+0.1100000(10000个表块)=11002个逻辑读 重建以后的成本:1个根+1个分支+0.15000(500个叶子)+0.1100000(10000个表块)=10502个逻辑读 性能提升百分比:4.5%(也就是减小了500个逻辑读)
  1. 若是经过索引获取100000条记录(占总记录数的10%)来讲,分两种状况: 对于快速全索引扫描来讲,假设每次获取8个数据块: 重建以前的成本:(1个根+40个分支+10000个叶子)/ 8=1256个逻辑读 重建以后的成本:(1个根+40个分支+5000个叶子)/ 8=631个逻辑读 性能提升百分比:49.8%(也就是减小了625个逻辑读)

从上面有关性能提升的理论描述能够看出,对于经过索引获取的记录行数不大的状况下,索引碎片对于性能的影响很是小;当经过索引获取较大的记录行数时,索引碎片的增长可能致使对于索引逻辑读的增长,可是索引读与表读的比例保持不变;同时,咱们从中能够看到,clustering_factor对于索引读取的性能有很大的影响,而且对于索引碎片所带来的影响具备很大的做用;最后,看起来,索引碎片彷佛对于快速全索引扫描具备最大的影响。

咱们来看两个实际的例子,分别是clustering_factor为最好和最差的两个例子。测试环境为8KB的数据块,表空间采用ASSM的管理方式。先作一个最好的clustering_factor的例子,建立测试表并填充1百万条数据。

create table rebuild_test(id number, name varchar2(10));

begin
    for i in 1..1000000 loop
        insert into rebuild_test values(i, to_char(i));
        if mod(i, 10000)=0 then
            commit;
        end if;
   end loop;
end;
/

#建立一个pctfree为50%的索引,来模拟索引碎片,分析并记录索引信息。
SQL> create index idx_rebuild_test on rebuild_test(id) pctfree 50;

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'rebuild_test',cascade=>true);

PL/SQL procedure successfully completed.

#该表具备1百万条记录,分布在2328个数据块中。同时因为咱们的数据都是按照顺序递增插入的,因此能够知道,在id列上建立的索引都是具备最好的clustering_factor值的。咱们运行如下查询测试语句,分别返回一、100、1000、10000、50000、100000以及1000000条记录。

#而后运行测试语句,记录每条查询语句所需的时间;
select * from rebuild_test where id = 10;

select * from rebuild_test where id between 100 and 199;

select * from rebuild_test where id between 1000 and 1999;

select * from rebuild_test where id between 10000 and 19999;

select /*+ index(rebuild_test) */ * from rebuild_test where id between 50000 and 99999;

select /*+ index(rebuild_test) */ * from rebuild_test where id between 100000 and 199999;

select /*+ index(rebuild_test) */ * from rebuild_test where id between 1 and 1000000;

select /*+ index_ffs(rebuild_test) */ id from rebuild_test where id between 1 and 1000000;

#注index_ffs: hint instructs the optimizer to perform a fast full index scan rather than a full table scan.

#接下来以pctfree为10%重建索引,来模拟修复索引碎片,分析并记录索引信息。

SQL> alter index idx_rebuild_test rebuild pctfree 10;

Index altered.

SQL> exec dbms_stats.gather_table_stats(user,'rebuild_test',cascade=>true);

PL/SQL procedure successfully completed.

SQL> analyze index idx_rebuild_test validate structure;

Index analyzed.

#两个索引信息的对比状况
select ui.pct_free, ids.height, ids.BLOCKS, ids.br_blks, ids.lf_blks, ids.pct_used, ui.clustering_factor
from index_stats ids, user_indexes ui 
where INDEX_NAME = 'IDX_REBUILD_TEST';
   
  PCT_FREE     HEIGHT     BLOCKS    BR_BLKS    LF_BLKS   PCT_USED CLUSTERING_FACTOR
---------- ---------- ---------- ---------- ---------- ---------- -----------------
        50          3       4224          8       4096         49              2326

  PCT_FREE     HEIGHT     BLOCKS    BR_BLKS    LF_BLKS   PCT_USED CLUSTERING_FACTOR
---------- ---------- ---------- ---------- ---------- ---------- -----------------
        10          3       2304          5       2226         90              2326

显示了不一样的索引下,运行测试语句所需的时间对比状况

记录数 占记录总数的百分比 pctused(50%) pctused(90%) 性能提升百分比
1条记录 0.0001% 0.01 0.01 0.00%
100条记录 0.0100% 0.01 0.01 0.00%
1000条记录 0.1000% 0.01 0.01 0.00%
10000条记录 1.0000% 0.02 0.02 0.00%
50000条记录 5.0000% 0.06 0.06 0.00%
100000条记录 10.0000% 1.01 1.00 0.99%
1000000条记录 100.0000% 13.05 11.01 15.63%=(13.05-11.01)/13.05
1000000条记录(FFS) 100.0000% 7.05 7.02 0.43%

上面是对最好的clustering_factor所作的测试,那么对于最差的clustering_factor会怎么样呢?咱们将rebuild_test中的id值反过来排列,也就是说,好比对于id为3478的记录,将id改成8743。这样的话,就将把原来按顺序排列的id值完全打乱,从而使得id上的索引的clustering_factor变成最差的。为此,我写了一个函数用来反转id的值。

CREATE OR REPLACE FUNCTION get_reverse_value (id IN NUMBER)
   RETURN VARCHAR2
IS
   ls_id          VARCHAR2 (10);
   ls_last_item   VARCHAR2 (10);
   ls_curr_item   VARCHAR2 (10);
   ls_zero        VARCHAR2 (10);
   li_len         INTEGER;
   lb_stop        BOOLEAN;
BEGIN
   ls_id := TO_CHAR (id);
   li_len := LENGTH (ls_id);
   ls_last_item := '';
   ls_zero := '';
   lb_stop := FALSE;

   WHILE li_len > 0
   LOOP
      ls_curr_item := SUBSTR (ls_id, li_len, 1);

      IF ls_curr_item = '0' AND lb_stop = FALSE
      THEN
         ls_zero := ls_zero || ls_curr_item;
      ELSE
         lb_stop := TRUE;
         ls_last_item := ls_last_item || ls_curr_item;  
      END IF;

      ls_id := SUBSTR (ls_id, 1, li_len - 1);
      li_len := LENGTH (ls_id);
   END LOOP;

   RETURN (ls_last_item || ls_zero);
END get_reverse_value;

/*
此程序以下:例如 123
循环1: ls_curr_item=3, ls_last_item= '||3=3, ls_id=12, li_en=2
循环2:ls_curr_item=2, ls_last_item=3||2=32, ls_id=1, li_en=1
循环3:ls_curr_item=1, ls_last_item=32||1=321, ls_id='', li_en=0
此时 li_en=0 跳出循环,返回 ls_last_item=321

例如100
循环1: ls_curr_item=0, ls_zero= ''||0=0, ls_id=20, li_en=2
循环2:ls_curr_item=0, ls_zero=0||0=00, ls_id=1, li_en=1
循环3:ls_curr_item=1, ls_last_item=''||1=1, ls_id='', li_en=0
此时 li_en=0 跳出循环,返回 ls_last_item=1,ls_zero=00,ls_last_item || ls_zero=100
*/

SQL> create table rebuild_test_cf as select * from rebuild_test;

Table created.

SQL> update rebuild_test_cf set id=get_reverse_value(id);

1000000 rows updated.

SQL> select * from rebuild_test_cf where name < 20;

        ID NAME
---------- ----------
        21 12
        31 13
        41 14
        51 15
        61 16
        71 17
        81 18
        91 19

SQL> create index idx_rebuild_test_cf on rebuild_test_cf(id);

Index created.

select ui.pct_free, ids.height, ids.BLOCKS, ids.br_blks, ids.lf_blks, ids.pct_used, ui.clustering_factor
from index_stats ids, user_indexes ui
where INDEX_NAME = 'IDX_REBUILD_TEST_CF';

  PCT_FREE     HEIGHT     BLOCKS    BR_BLKS    LF_BLKS   PCT_USED CLUSTERING_FACTOR
---------- ---------- ---------- ---------- ---------- ---------- -----------------
        10          3       2304          5       2226         90            998914

SQL> select /*+ index(rebuild_test_cf) */ * from rebuild_test_cf where id between 1 and 1000000;

1000000 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 509582566

-------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                | Rows  | Bytes | Cost (%CPU)| Time   |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                     |  1000K|    11M|  1001K  (1)|03:20:18|
|   1 |  TABLE ACCESS BY INDEX ROWID| REBUILD_TEST_CF     |  1000K|    11M|  1001K  (1)|03:20:18|
|*  2 |   INDEX RANGE SCAN          | IDX_REBUILD_TEST_CF |  1000K|       |  2238   (1)|00:00:27|
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID">=1 AND "ID"<=1000000)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
    1067727  consistent gets
       1938  physical reads
          0  redo size
   29269206  bytes sent via SQL*Net to client
     733850  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
    1000000  rows processed

SQL> select /*+ index_ffs(rebuild_test_cf) */ id from rebuild_test_cf where id between 1 and 1000000;

1000000 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3567300343

--------------------------------------------------------------------------------------------
| Id  | Operation            | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                     |  1000K|  4882K|   616   (2)| 00:00:08 |
|*  1 |  INDEX FAST FULL SCAN| IDX_REBUILD_TEST_CF |  1000K|  4882K|   616   (2)| 00:00:08 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("ID">=1 AND "ID"<=1000000)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      68759  consistent gets
       2190  physical reads
          0  redo size
   18380300  bytes sent via SQL*Net to client
     733850  bytes received via SQL*Net from client
      66668  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
    1000000  rows processed
相关文章
相关标签/搜索