Oracle之函式索引

lhrbest發表於2017-11-28

Oracle之函式索引




Oracle中,有一類特殊的索引,稱為函式索引(Function-Based IndexesFBI),它基於對錶中列進行計算後的結果建立索引。函式索引在不修改應用程式的邏輯基礎上提高了查詢效能。如果沒有函式索引,那麼任何在列上執行了函式的查詢都不能使用這個列的索引。當在查詢中包含該函式時,資料庫才會使用該函式索引。函式索引可以是一個B-Tree索引或點陣圖索引。

用於生成索引的函式可以是算術表示式,也可以是一個包含SQL函式、使用者定義PL/SQL函式、包函式,或C呼叫的表示式。當資料庫處理INSERTUPDATE語句時,它仍然必須計算函式才能完成對語句的處理。

對於函式索引的索引列的函式查詢可以透過檢視DBA_IND_EXPRESSIONS來實現,透過如下的SQL語句可以查詢所有的函式索引:

SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE LIKE 'FUNCTION-BASED%';

函式索引必須遵守下面的規則:

① 必須使用基於成本的最佳化器,而且建立後必須對索引進行分析。

② 如果被函式索引所引用的使用者自定義PL/SQL函式失效了或該函式索引的屬主沒有了在函式索引裡面使用的函式的執行許可權,那麼對這張表上的執行的所有的操作(例如SELECT查詢、DML等)也將失敗(會報錯:ORA-06575: Package or function F_R1_LHR is in an invalid stateORA-00904: : invalid identifier)。這時,可以重新修改自定義函式並在編譯無報錯透過後,該表上所有的DML和查詢操作將恢復正常。

③ 建立函式索引的函式必須是確定性的。即,對於指定的輸入,總是會返回確定的結果。

④ 在建立索引的函式里面不能使用SUMCOUNT等聚合函式。

⑤ 不能在LOB型別的列、NESTED TABLE列上建立函式索引。

⑥ 不能使用SYSDATEUSER等非確定性函式。

⑦ 對於任何使用者自定義函式必須顯式的宣告DETERMINISTIC關鍵字,否則會報錯:“ora-30553: the function is not deterministic”。

需要注意的是,使用函式索引有幾個先決條件:

(1)必須擁有CREATE INDEXQUERY REWRITE(本模式下)或CREATE ANY INDEXGLOBAL QUERY REWRITE其它模式下)許可權。其賦權語句分別為GRANT QUERY REWRITE TO LHR;”和“GRANT GLOBAL QUERY REWRITE TO LHR;”。

(2)必須使用基於成本的最佳化器,基於規則的最佳化器將被忽略。

(3)引數QUERY_REWRITE_INTEGRITYQUERY_REWRITE_ENABLED可以保持預設值。

QUERY_REWRITE_INTEGRITY = ENFORCED

QUERY_REWRITE_ENABLED = TRUE(從Oracle 10g開始預設為TRUE

這裡舉一個基於函式的索引的例子

首先為函式索引建立及資料準備:

SYS@lhrdb> CREATE TABLE TESTFINDEX_LHR(ID NUMBER,SCHR VARCHAR2(10));

Table created.

SYS@lhrdb> CREATE INDEX IND_FUN ON TESTFINDEX_LHR(UPPER(SCHR));

Index created.

SYS@lhrdb> INSERT INTO TESTFINDEX_LHR VALUES(1,'a');

1 row created.

SYS@lhrdb> COMMIT;

Commit complete.

因為強制使用基於規則的最佳化器,所以,不會使用函式索引:

SYS@lhrdb> SELECT /*+ RULE*/ * FROM TESTFINDEX_LHR WHERE UPPER(SCHR)='A';

        ID SCHR

---------- ----------

         1 a

Execution Plan

----------------------------------------------------------

Plan hash value: 940247041

--------------------------------------------

| Id  | Operation         | Name           |

--------------------------------------------

|   0 | SELECT STATEMENT  |                |

|*  1 |  TABLE ACCESS FULL| TESTFINDEX_LHR |

--------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter(UPPER("SCHR")='A')

Note

-----

   - rule based optimizer used (consider using cbo)

這裡最佳化器選擇了全表掃描,若在不使用基於規則的最佳化器的情況下,則該查詢會選擇函式索引IND_FUN

SYS@lhrdb> SELECT  * FROM TESTFINDEX_LHR WHERE UPPER(SCHR)='A';

        ID SCHR

---------- ----------

         1 a

Execution Plan

----------------------------------------------------------

Plan hash value: 967513602

----------------------------------------------------------------------------------------------

| Id  | Operation                   | Name           | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                |     1 |    27 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TESTFINDEX_LHR |     1 |    27 |     1   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IND_FUN        |     1 |       |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access(UPPER("SCHR")='A')

Note

-----

   - dynamic sampling used for this statement (level=2)

SYS@lhrdb> SELECT D.TABLE_NAME,D.COLUMN_EXPRESSION FROM DBA_IND_EXPRESSIONS D WHERE D.INDEX_NAME='IND_FUN';

 

TABLE_NAME                     COLUMN_EXPRESSION

------------------------------ ----------------------

TESTFINDEX_LHR                 UPPER("SCHR")

可見,例子中使用了IND_FUN函式索引,且函式可以透過檢視DBA_IND_EXPRESSIONS來查詢。






原文地址:說說函式索引 作者:realkid4


我們進行資料庫檢索最佳化的方法,通常是對特定條件列加索引,減少由於全表掃描帶來的邏輯物理IO消耗。索引的種類很多,我們經常使用的B*樹索引,由於結構簡單、適應性強,可以應對大多數資料訪問最佳化需求。除B*樹索引外,其他一些索引型別,也在一些場合中扮演著獨特的地位。本篇來介紹其中的函式索引。

 

1、從B*樹索引的失效談起

 

和通常一樣,我們準備實驗環境。

 

 

SQL> select * from v$version where rownum<2;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

 

SQL> create table t as select * from dba_objects;

Table created

//構建兩個索引用作實驗物件

SQL> create index idx_t_owner on t(owner);

Index created

 

SQL> create index idx_t_ddlt on t(last_ddl_time);

Index created

 

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

PL/SQL procedure successfully completed

 

 

環境中,我們在資料表T上建立了一般意義的索引。當我們進行檢索的時候,CBO會適時選擇合適的索引執行計劃。

 

 

SQL> explain plan for select * from t where owner='SCOTT';

Explained

 

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1516787156

--------------------------------------------------------------------------------

| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)|

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |             |  2419 |   229K|    71   (0)|

|   1 |  TABLE ACCESS BY INDEX ROWID| T           |  2419 |   229K|    71   (0)|

|*  2 |   INDEX RANGE SCAN          | IDX_T_OWNER |  2419 |       |     6   (0)|

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("OWNER"='SCOTT')

14 rows selected

 

 

但是,很多時候,我們可能會遇到在where條件裡對索引列進行函式處理的情況。比如,選擇owner列取值第二個字母是“c”的資料列,或者選取在特定天進行ddl操作的物件資訊。這樣的情況下,直接的想法就是在where條件列中加入列函式處理,但是這樣做,會帶來B*樹索引的失效問題。

 

SQL> explain plan for select * from t where substr(owner,2,1)='C';

Explained

 

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 1601196873

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |   726 | 70422 |   283   (1)| 00:00:04 |

|*  1 |  TABLE ACCESS FULL| T    |   726 | 70422 |   283   (1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter(SUBSTR("OWNER",2,1)='C')

13 rows selected

 

 

 

在對條件列owner進行substr操作之後,生成的執行計劃就不會帶有索引路徑,出現全表掃描。如果列上的B*樹普通索引就是為該查詢對應的用例服務的,那麼這個索引的存在就失去了意義。

 

 

那麼,這種時候應該如何處理呢?答案是:在SQL語句本身不存在重構最佳化的空間時(此種情況通常出現在系統的運維階段),可以考慮使用函式索引來解決問題。

 

2、函式索引

 

函式索引與通常B*樹索引的結構,存在很大相似性。區別就在於形成樹結構的葉子節點上,儲存的不是索引列的取值,而是經過特定的函式處理過的索引列值。

 

 

這樣的結構,進行搜尋的時候,就可以直接使用到函式索引的葉子節點,獲取到對應的rowid集合。要求是出現於構建函式索引完全相同的函式條件。

 

首先,我們來構建函式索引。

 

 

SQL> create index idx_t_ownerf on t(substr(owner,2,1));

Index created

 

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

PL/SQL procedure successfully completed

 

 

構建函式索引的語法和一般索引的語法沒有過多的區別,最大的差異就是在宣告索引列的位置上,寫清楚應用的函式語句。此時,資料字典檢視系列中,已經反映出函式索引的不同。

 

 

SQL> select index_type from dba_indexes where index_name='IDX_T_OWNERF';

INDEX_TYPE

---------------------------

FUNCTION-BASED NORMAL

 

 

此時,我們再進行查詢,執行計劃會發生變化。

 

 

SQL> explain plan for select * from t where substr(owner,2,1)='C';

Explained

 

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 2485331276

--------------------------------------------------------------------------------

| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |              |  4839 |   467K|   135   (0)

|   1 |  TABLE ACCESS BY INDEX ROWID| T            |  4839 |   467K|   135   (0)

|*  2 |   INDEX RANGE SCAN          | IDX_T_OWNERF |  4839 |       |     9   (0)

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access(SUBSTR("OWNER",2,1)='C')

14 rows selected

 

 

 

加入函式索引之後,我們可以發現同樣的SQL語句,執行計劃發生變化。函式索引開始起效。

 

那麼,函式索引的本質是什麼呢?我們檢查資料字典檢視,就可以發現函式索引的本質。

 

SQL> col table_name for a20;

SQL> col table_owner for a20;

SQL> col column_name for a30;

SQL> select table_owner, table_name, column_name from dba_ind_columns where index_name='IDX_T_OWNERF';

 

TABLE_OWNER          TABLE_NAME           COLUMN_NAME

-------------------- -------------------- ------------------------------

SYS                  T                    SYS_NC00016$

 

SQL> select column_expression from dba_ind_expressions where index_name = 'IDX_T_OWNERF';

 

COLUMN_EXPRESSION

-------------------------------------

SUBSTR("OWNER",2,1)

 

SQL> select column_name,data_type,data_default from dba_tab_cols where wner='SYS' and table_name='T' and column_name='SYS_NC00016$';

 

COLUMN_NAME          DATA_TYPE            DATA_DEFAULT

-------------------- -------

SYS_NC00016$         VARCHAR2             SUBSTR("OWNER",2,1)

 

 

檢查了三個檢視的情況,我們可以清楚的看出Oracle函式索引的本質。Oracle建立函式索引之後,就會先建立出一個不可見的內部列(SYS_NC00016$)。之後,對這個列建立普通的B*樹索引。為了保證該列在不受影響的情況下進行資料生成,使用預設值技術,在資料插入或者變化的時候,進行同步。

 

 

3、函式索引使用

 

函式索引是一種很特殊的索引型別,可以應對開發階段出現的對資料列加函式處理SQL最佳化。但是,筆者以為,函式索引的使用還是應當注意一些細節的,在大部分場合下,函式索引可以作為一種應急或者是不得為之的策略。

 

首先,函式索引的綜合消耗要大於普通的B*樹索引。相對於傳統索引,函式索引要保證創造的函式列資料一致性和多次進行函式計算。這樣的消耗要遠大於普通B*樹索引;

 

其次,函式索引的適應範圍較小。函式索引其效果的最大要素就是函式的使用和定義是100%相同。如第二部分的例子中,取字串的第二位字串。如果有一個變更的需求,要求取第三位,這樣原來的那個函式索引就不能發揮效應了。而相對來說,普通的B*樹索引參與各種SQL的能力要很多。應該說,函式索引的針對性很強,如果這個需求不屬於關鍵需求,這樣價效比略差。

 

 

最後,函式索引通常是一種事後補救措施。筆者認為,一個良好設計的應用,一個劃分合理的資料庫邏輯結構,應該是可以避免函式運算元據列的SQL大量出現的。只有在系統上線之後,開發團隊開發的問題暴露出來,但是也沒有精力進行修改時,運維人員才開始使用函式索引,保證系統功能能夠實現。

 

 

對開發人員和開發DBA而言,函式索引通常是不得已為之的方案,要保證在SQL和資料表結構權衡無效的情況下,再考慮使用函式索引。

 

首先,考慮SQL結構的最佳化。這個方法可以消滅掉很多看似不得不使用函式索引的場合。如字串型別比較、日期匹配等等,都可以透過程式碼檢查和SQL改寫來避免進入函式索引的狀況。下面一個例子:

 

 

//獲取前一天進行ddl操作的物件列表

SQL> select count(*) from t where trunc(last_ddl_time)=trunc(sysdate)-1;

 

  COUNT(*)

----------

         9

 

 

日期型操作最大的問題就是時分秒結構的處理。Date型別本身是帶有時分秒資訊的,而進行查詢的時候,常常是使用特定的年月日。這樣,就會帶來一些檢索條件的問題。很多開發人員,就是直接使用trunc函式,將資料列上的時分秒資訊進行裁剪。這樣的確簡單,而且滿足需求。但是也留下了列索引失效的隱患。

 

 

正確的解決方式,應該將SQL進行改寫,變等於條件為範圍條件。如下:

 

 

SQL> explain plan for select count(*) from t where last_ddl_time between to_date('2011-5-20 00:00:00','yyyy-mm-dd hh24:mi:ss')

  2   and to_date('2011-5-20 23:59:59','yyyy-mm-dd hh24:mi:ss');

 

Explained

 

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------

Plan hash value: 3824876144

--------------------------------------------------------------------------------

| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |            |     1 |     8 |     2   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE   |            |     1 |     8 |            |          |

|*  2 |   INDEX RANGE SCAN| IDX_T_DDLT |    91 |   728 |     2   (0)| 00:00:01 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("LAST_DDL_TIME">=TO_DATE(' 2011-05-20 00:00:00',

              'syyyy-mm-dd hh24:mi:ss') AND "LAST_DDL_TIME"<=TO_DATE(' 2011-05-2

              23:59:59', 'syyyy-mm-dd hh24:mi:ss'))

 

16 rows selected

 

 

經過改寫,沒有使用函式索引,原有的B*樹索引起效。很多時候,經過SQL的重新思考,是可以避免函式索引使用場合出現的。特別是在專案的開發階段,這個尤為重要。

 

 

其次,就是對設計表的改進。我們常說一正規化:列不可分。如果出現很多的對資料列的函式處理,我們就需要重新審視我們的設計表方案。是不是存在設計不合理、沒有考慮到實際業務技術需求的方面。當SQL沒有最佳化空間時,設計表的重構,冗餘欄位的加入可能是比較好的思路方法。

 

 

 

4、結論

 

本篇從一般的函式索引,談到了SQL的改寫和設計表最佳化。核心要義就是一點,慎用函式索引。而且,在絕大多數的情況下,我們是不需要使用函式索引的。只要能夠理智冷靜的分析實際需求和SQL結構,通常都可以獲取到一個折中的方案。





Oracle中利用函式索引處理資料傾斜案例 

首先宣告:本方法是受到dbsnake的指導,再次感謝指點。

 

通常來說,索引選取的資料列最好為分散度高、選擇性好。從索引樹結構的角度看,列值都是分佈在葉節點位置。這樣,透過樹結構搜尋得到的葉節點數量效率比較高。

 

實際中,我們常常遇到資料列值傾斜的情況。就是說,整個列資料取值有限。但是大部分資料值都集中在少數一兩個取值裡,其他取值比例極少。比如:一個資料列值有“N”、“B”、“M”、“P”、“Q”幾個取值,其中55%資料行取值為“N”,40%資料行取值為“B”,剩下的取值分佈在5%的資料行中。對於這種結構的資料列加索引,是存在一些問題的。

 

首先,預設資料庫是會為所有的列值(非空)建立索引結構。也就意味著無論是高頻度取值,還是低頻度取值,都會在索引結構的葉節點上出現。當然,這樣的大部分葉節點都是這些重複值。

 

其次,在CBO(基於成本最佳化器)的作用下,對高頻度取值的搜尋一般都不會選擇索引作為搜尋路徑,因為進行全表掃描可能效率更高。我們為資料列建立了索引,但高頻詞的查詢永遠不會走到索引路徑。

 

最後,建立的索引空間和時間消耗比較大。建立的索引涵蓋所有取值,對海量資料表而言,佔有的空間勢必較大。同時,在進行小頻度資料查詢的時候,雖然會去走索引路徑,但是引起的邏輯物理讀也是有一些損耗。

 

 

引入一個解決方法,思路:既然高頻度值在查詢的時候不會走到索引路徑,可以考慮將其剔出構建索引的過程,只為那些低頻度資料值建立索引結構。這樣,建立的索引樹結構相對較小,而且索引查詢的效率也能提升。

 

具體的方法是使用decode函式。decode(a,b,c,d,ef)含義:如果a=b,則返回c,等於d,返回e,最後沒有匹配的情況下,返回f。針對上面的例子,可以使用decode(列名,‘N, null, B, null, 列名),含義是,如果該列取值為N或者B,直接設定為null,否則才返回列值。並且以此建立函式索引。

 

這樣做藉助了Oracle兩個功能:1、對null值不生成索引;2、函式索引;

 

下面的實驗證明了該方法:

 

1、  構建資料環境

 

//資料準備

SQL> create table t as select * from dba_objects where 1=0;

 

Table created

//構造大資料環境,使用指令碼

declare

  i number;

begin 

  for i in 1..40 loop    

     insert /*+ append */ into t

     select * from dba_objects;

    

     commit; 

  end loop;

end;

/

 

SQL> select count(*) from t;

 

  COUNT(*)

----------

   4759209

 

Executed in 15.522 seconds

 

整理後的資料環境如下:

 

//投入實驗的資料狀態

SQL> select secondary, count(*) from t group by secondary;

 

SECONDARY   COUNT(*)

--------- ----------

W                273

Q                  9

D                273

T             421230

J            1866592

E                 99

S            2470733

 

7 rows selected

 

Executed in 18.002 seconds

 

可以看到,近五百萬資料兩種,絕大部分資料集中到了S、T、J上,其他資料取值頻數較小。資料傾斜趨勢明顯。

 

2、  建索引

分別對secondary列建立常規、函式索引。

 

SQL>create index IND_SEC_NORMAL on t(secondary);

Index created

SQL> create index ind_t_fun on t(decode (secondary, 'S', null, 'J', null, 'T', null, secondary ));

Index created

Executed in 28.049 seconds

 

索引ind_t_fun將S、T、J值轉化為null,剔出了建立索引的過程。從索引段資訊看,兩個索引所佔的空間差異比較大,也證明了這點。

 

SQL> select * from dba_segments where segment_name='IND_SEC_NORMAL';

 

OWNER    SEGMENT_NAME  SEGMENT_TYPE             BYTES     BLOCKS    EXTENTS

-------  ------------- ------------------  ---------- ---------- ----------

SYS      IND_T_FUN     INDEX                 75497472       9216         80  

 

Executed in 0.733 seconds

 

SQL> select * from dba_segments where segment_name=upper('ind_t_fun');

 

OWNER  SEGMENT_NAME  SEGMENT_TYPE          BYTES     BLOCKS    EXTENTS

------ ------------- --------------   ---------- ---------- ----------

SYS    IND_T_FUN     INDEX                 65536          8          1  

 

Executed in 0.156 seconds

注:本結果經過額外處理,用於方便顯示;

 

可以看出,同樣是對一個資料列加索引。普通索引型別Ind_sec_normal佔據80個區,9216個資料塊,空間約佔75.5M。而函式索引ind_t_fun的空間只用了初始分配的1個區,8個資料塊,空間約佔65K。由此,空間優勢立現!

 

收集統計資料,由於是實驗性質,而且資料量大,採用高取樣率收集統計資訊。

 

SQL> exec dbms_stats.gather_table_stats(user, 'T', cascade => true, estimate_percent => 100,method_opt => 'for all indexed columns');

 

PL/SQL procedure successfully completed

 

Executed in 60.403 seconds

 

 

3、  檢索效率分析

 

針對資料量273的W取值進行分析。

直接索引搜尋:

 

SQL> select * from t where secondary='W';

 

已選擇273行。

 

已用時間:  00: 00: 00.37

 

執行計劃

----------------------------------------------------------

Plan hash value: 1573525374

 

--------------------------------------------------------------------------------

| Id  | Operation                   | Name           | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                |   273 | 25935 |    11   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T              |   273 | 25935 |    11   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IND_SEC_NORMAL |   273 |       |     3   (0)| 00:00:01 |

----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("SECONDARY"='W')

 

統計資訊

----------------------------------------------------------

        775  recursive calls

          0  db block gets

        272  consistent gets

         21  physical reads

          0  redo size

      28339  bytes sent via SQL*Net to client

        583  bytes received via SQL*Net from client

         20  SQL*Net roundtrips to/from client

         16  sorts (memory)

          0  sorts (disk)

        273  rows processed

 

發現採用W作為搜尋值時,是進行了索引搜尋。下面是用函式索引搜尋進行對比。

 

SQL> select * from t where decode(secondary,'S',null,'J',null,'T',null,secondary)='W';

 

已選擇273行。

 

已用時間:  00: 00: 00.04

 

執行計劃

----------------------------------------------------------

Plan hash value: 3192598969

-----------------------------------------------------------------------------------------

| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

-----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |           |   273 | 25935 |   116   (0)| 00:00:02 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T         |   273 | 25935 |   116   (0)| 00:00:02 |

|*  2 |   INDEX RANGE SCAN          | IND_T_FUN |   273 |       |     1   (0)| 00:00:01 |

-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access(DECODE("SECONDARY",'S',NULL,'J',NULL,'T',NULL,"SECONDARY")='W')

 

統計資訊

----------------------------------------------------------

         45  recursive calls

          0  db block gets

        140  consistent gets

          0  physical reads

          0  redo size

      13225  bytes sent via SQL*Net to client

        583  bytes received via SQL*Net from client

         20  SQL*Net roundtrips to/from client

          1  sorts (memory)

          0  sorts (disk)

        273  rows processed

 

對比後,我們可以發現,使用函式索引的方法,在執行時間、物理邏輯讀、CPU使用上有一定差異。

 

 

普通索引

函式索引

執行時間

00: 00: 00.37

00: 00: 00.04

CPU使用

11

116

consistent gets

272

140

physical reads

21

0

 

結論:使用函式索引處理偏值方法,在一定長度上最佳化查詢效率和索引結構。上表的資料表明,會使邏輯物理讀的消耗很大程度的減少(索引結構簡化),同時連帶影響執行時間的縮小。因為使用函式要進行計算,CPU使用率相對較高,在可以接受的範圍內。

 

但是,這種方法是存在一些限制的,應用前一定要仔細規劃。

首先,資料表資料要保證較大。因為畢竟函式索引的建立和搜尋較普通索引消耗大,如果資料表小,帶來的最佳化程度不能彌補消耗的成本,結果可能得不償失。筆者進行的一系列實驗中,也發現在資料量中等偏小時,這種效能優勢不能凸顯。

 

其次,列值傾斜趨勢明顯。透過開篇的討論我們不難發現,列值傾斜的程度越高,使用函式索引剔出的資料量也就越大,生成的索引樹結構也就越小越最佳化。這一點是本方法的核心!

 

最後,使用函式索引搜尋時,搜尋的取值頻數越高,最佳化效果越好。在本例中,取值W的列有273行,可以看出明顯的效能最佳化。當我們選擇值有9條資料的Q值時,這種最佳化趨勢可以看到,但是明顯程度降低(實驗結果略)。這裡的原因可能是資料量小時,兩種方法邏輯物理讀的差異度縮小。





About Me

.............................................................................................................................................

● 本文作者:小麥苗,部分內容整理自網路,若有侵權請聯絡小麥苗刪除

● 本文在itpub(http://blog.itpub.net/26736162/abstract/1/)、部落格園(http://www.cnblogs.com/lhrbest)和個人微信公眾號(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文部落格園地址:http://www.cnblogs.com/lhrbest

● 本文pdf版、個人簡介及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● DBA寶典今日頭條號地址:

.............................................................................................................................................

● QQ群號:230161599(滿)、618766405

● 微信群:可加我微信,我拉大家進群,非誠勿擾

● 聯絡我請加QQ好友646634621,註明新增緣由

● 於 2017-11-01 09:00 ~ 2017-11-30 22:00 在魔都完成

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

.............................................................................................................................................

小麥苗的微店

小麥苗出版的資料庫類叢書http://blog.itpub.net/26736162/viewspace-2142121/

.............................................................................................................................................

使用微信客戶端掃描下面的二維碼來關注小麥苗的微信公眾號(xiaomaimiaolhr)及QQ群(DBA寶典),學習最實用的資料庫技術。

   小麥苗的微信公眾號      小麥苗的DBA寶典QQ群2     《DBA筆試面寶典》讀者群       小麥苗的微店

.............................................................................................................................................

Oracle之函式索引
DBA筆試面試講解群
《DBA寶典》讀者群 歡迎與我聯絡



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2147880/,如需轉載,請註明出處,否則將追究法律責任。

相關文章