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
相關文章
相關標籤/搜索