Oracle效能最佳化之虛擬索引

datapeng發表於2016-04-15

虛擬索引是定義在資料字典中的偽索引,但沒有相關的索引段。虛擬索引的目的是模擬索引的存--而不用真實的建立一個完整索引。這允許開發者建立虛擬索引來檢視相關執行計劃而不用等到真實建立完索引才能檢視索引對執行計劃的影響,並且不會增加儲存空間的使用。如果我們觀察到最佳化器生成了一個昂貴的執行計劃並且SQL調整指導建議我們對某些的某列建立索引,但在生產資料庫環境中建立索引與測試並不總是可以操作。我們需要確保建立的索引將不會對資料庫中的其它查詢產生負面影響,因此可以使用虛擬索引。

下面舉例進行說明
1.建立一個測試表test

SQL> create table test as select * from dba_objects;

Table created.

2.從表test查詢object_name等於standard的記錄

SQL> select * from test where object_name='STANDARD';

OWNER
------------------------------
OBJECT_NAME
--------------------------------------------------------------------------------
SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
------------------------------ ---------- -------------- -------------------
CREATED      LAST_DDL_TIM TIMESTAMP           STATUS  T G S
------------ ------------ ------------------- ------- - - -
SYS
STANDARD
                                      888                PACKAGE
19-APR-10    19-APR-10    2003-04-18:00:00:00 VALID   N N N


OWNER
------------------------------
OBJECT_NAME
--------------------------------------------------------------------------------
SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE
------------------------------ ---------- -------------- -------------------
CREATED      LAST_DDL_TIM TIMESTAMP           STATUS  T G S
------------ ------------ ------------------- ------- - - -
SYS
STANDARD
                                      889                PACKAGE BODY
19-APR-10    19-APR-10    2010-04-19:10:22:58 VALID   N N N

3.查詢上面查詢的執行計劃

SQL> set autotrace traceonly explain
SQL> select * from test where object_name='STANDARD';

Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     8 |  1416 |   155   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TEST |     8 |  1416 |   155   (1)| 00:00:02 |
--------------------------------------------------------------------------

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

   1 - filter("OBJECT_NAME"='STANDARD')

Note
-----
   - dynamic sampling used for this statement

4.在表test的object_name列上建立一個虛擬索引

SQL> create index test_index on test(object_name) nosegment;

Index created.

為了建立虛擬索引必須在create index語句中指定nosegment子句,並且不會建立索引段。

5.來驗證虛擬索引不會建立索引段

SQL> set autotrace off
SQL> select index_name from dba_indexes where table_name = 'TEST' and index_name = 'TEST_INDEX';

no rows selected

SQL> col OBJECT_NAME format a20;
SQL> select object_name, object_type from dba_objects where object_name = 'TEST_INDEX';

OBJECT_NAME          OBJECT_TYPE
-------------------- -------------------
TEST_INDEX           INDEX

從上面的結果可以看到索引物件已經建立,但沒有建立索引段。

6.重新執行sql檢視建立的虛擬索引是否被使用

SQL> set autotrace traceonly explain
SQL> select * from test where object_name='STANDARD';

Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     8 |  1416 |   155   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TEST |     8 |  1416 |   155   (1)| 00:00:02 |
--------------------------------------------------------------------------

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

   1 - filter("OBJECT_NAME"='STANDARD')

Note
-----
   - dynamic sampling used for this statement

從上面的執行計劃可以清楚地看到建立的虛擬索引並沒有被使用

7.為了能使用所建立的虛擬索引,需要將_USE_NOSEGMENT_INDEXES設定為true

SQL> alter session set "_USE_NOSEGMENT_INDEXES" = true;

Session altered.

8.重新執行sql檢視建立的虛擬索引是否被使用

SQL> set long 900
SQL> set linesize 900
SQL> select * from test where object_name='STANDARD';

Execution Plan
----------------------------------------------------------
Plan hash value: 2627321457

------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |     8 |  1416 |     5   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST       |     8 |  1416 |     5   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | TEST_INDEX |   238 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

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

   2 - access("OBJECT_NAME"='STANDARD')

Note
-----
   - dynamic sampling used for this statement

從上面的執行計劃可以看到當設定隱含引數_USE_NOSEGMENT_INDEXES後,最佳化器將會使用建立的虛擬索引。在使用虛擬索引需要注意,我們可以分析虛擬索引,但不能重建虛擬索引,如果重建虛擬索引會收到ORA-8114: "User attempted to alter a fake index"錯誤提示,可以刪除虛擬索引。

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

相關文章