oracle利用索引關聯獲得資料的方法

xz43發表於2010-11-24
    and_equal,index_join,index_combine這三種都是oracle利用索引關聯獲得資料的方法,三者的目的都是為了最大限度的利用索引,減少回表的代價.但是三者的實現方法是有區別的,下面一一來分析。

and_equal:
這種方式需要查詢條件裡面包括所有索引列,然後取得每個索引中得到的rowid列表,然後對這些列表做merge join,過濾出相同的rowid後再去表中獲取資料或者直接從索引中獲得資料.and_equal有一些限制,比如它只對單列索引有效,只對非唯一索引有效,使用到的索引不能超過5個,查詢條件只能是”=”.在10g中,and_equal已經被廢棄了,只能透過hint才能生效.

create table test as select * from dba_objects;

create index ind_test_owner on test(owner);

create index ind_test_object_name on test(object_name);

SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’ and object_name=’test’;

Execution Plan
———————————————————-

——————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
——————————————————————————-
| 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
|* 1 | AND-EQUAL | | | | |
|* 2 | INDEX RANGE SCAN| IND_TEST_OWNER | 1 | | 1 (0)|
|* 3 | INDEX RANGE SCAN| IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
——————————————————————————-

如果查詢條件只包含owner

SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’;

Execution Plan
———————————————————-

———————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
———————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 29 | 2 (0)|
|* 2 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
———————————————————————————–

修改owner,object_name為非空

alter table test modify(owner not null);
alter table test modify(object_name not null);

SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’;

Execution Plan
———————————————————-

———————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
———————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 29 | 2 (0)|
|* 2 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
———————————————————————————–

效果一樣

查詢條件是”>”的情況

SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where owner>’test’ and object_name=’test’;

Execution Plan
———————————————————-

—————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
—————————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
|* 2 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
—————————————————————————————–

查詢條件是in的情況
SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where owner in(’test’,'dba’) and object_name=’test’;

Execution Plan
———————————————————-

—————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
—————————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
|* 2 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
—————————————————————————————–

再來看一下回表的情況

SQL 10G>select/*+ and_equal(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where wner=’test’ and object_name=’test’;

Execution Plan
———————————————————-

—————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
—————————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
| 2 | AND-EQUAL | | | | |
|* 3 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
|* 4 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | 2 | | 1 (0)|
—————————————————————————————–

先透過and_equal取得rowid列表,然後從表中返回資料.

index_join:
index join顧名思義是對index進行關聯,oracle透過hash index join的方式實現了避免對錶的訪問.所有的資料都從索引中直接獲得.它不受查詢條件影響,可以是唯一索引,也可以是多列索引.

SQL 10G>select/*+ index_join(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’ and object_name=’test’;

Execution Plan
———————————————————-

——————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
——————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 29 | 3 (34)|
|* 1 | VIEW | index$_join$_001 | 1 | 29 | 3 (34)|
|* 2 | HASH JOIN | | | | |
|* 3 | INDEX RANGE SCAN| IND_TEST_OWNER | 1 | 29 | 1 (0)|
|* 4 | INDEX RANGE SCAN| IND_TEST_OBJECT_NAME | 1 | 29 | 1 (0)|
——————————————————————————–

可以不帶查詢條件,只不過由index range scan變成了index fast full scan

SQL 10G>select/*+ index_join(test ind_test_owner ind_test_object_name)*/ owner,object_name from test
2 ;

Execution Plan
———————————————————-

————————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
————————————————————————————
| 0 | SELECT STATEMENT | | 51984 | 1472K| 478 (2)|
| 1 | VIEW | index$_join$_001 | 51984 | 1472K| 478 (2)|
|* 2 | HASH JOIN | | | | |
| 3 | INDEX FAST FULL SCAN| IND_TEST_OWNER | 51984 | 1472K| 153 (2)|
| 4 | INDEX FAST FULL SCAN| IND_TEST_OBJECT_NAME | 51984 | 1472K| 322 (1)|
————————————————————————————

如果不是所有資料都能從索引獲得,那麼將不會使用index join

SQL 10G>select/*+ index_join(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where wner=’test’ and object_name=’test’;

Execution Plan
———————————————————-

———————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
———————————————————————————–
| 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 40 | 2 (0)|
|* 2 | INDEX RANGE SCAN | IND_TEST_OWNER | 1 | | 1 (0)|
———————————————————————————–

index_combine:
index combine最早是用在bitmap index上的,在9i開始oracle預設可以使用在btree索引上,這是由_b_tree_bitmap_plans引數來控制的.oracle將btree索引中獲得的rowid資訊透過BITMAP CONVERSION FROM ROWIDS的步驟轉換成bitmap進行匹配,然後匹配完成後透過BITMAP CONVERSION TO ROWIDS再轉換出rowid獲得資料或者回表獲得資料.

SQL 10G>select/*+ index_combine(test ind_test_owner ind_test_object_name)*/ owner,object_name from test where wner=’test’ and object_name=’test’;

Execution Plan
———————————————————-

———————————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
———————————————————————————————
| 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)|
| 1 | BITMAP CONVERSION TO ROWIDS | | 1 | 29 | 2 (0)|
| 2 | BITMAP AND | | | | |
| 3 | BITMAP CONVERSION FROM ROWIDS| | | | |
|* 4 | INDEX RANGE SCAN | IND_TEST_OWNER | | | 1 (0)|
| 5 | BITMAP CONVERSION FROM ROWIDS| | | | |
|* 6 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | | | 1 (0)|
———————————————————————————————

回表取資料的情況

SQL 10G>select/*+ index_combine(test ind_test_owner ind_test_object_name)*/ owner,object_name,object_type from test where wner=’test’ and object_name=’test’;

Execution Plan
———————————————————-

———————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
———————————————————————————————-
| 0 | SELECT STATEMENT | | 1 | 40 | 2 (0)|
| 1 | TABLE ACCESS BY INDEX ROWID | TEST | 1 | 40 | 2 (0)|
| 2 | BITMAP CONVERSION TO ROWIDS | | | | |
| 3 | BITMAP AND | | | | |
| 4 | BITMAP CONVERSION FROM ROWIDS| | | | |
|* 5 | INDEX RANGE SCAN | IND_TEST_OWNER | | | 1 (0)|
| 6 | BITMAP CONVERSION FROM ROWIDS| | | | |
|* 7 | INDEX RANGE SCAN | IND_TEST_OBJECT_NAME | | | 1 (0)|
———————————————————————————————-

不帶查詢條件的情況,index combine將不被使用

SQL 10G>select/*+ index_combine(test ind_test_owner ind_test_object_name)*/ owner,object_name from test
2 ;

Execution Plan
———————————————————-

———————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
———————————————————————————–
| 0 | SELECT STATEMENT | | 51984 | 1472K| 1480 (1)|
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 51984 | 1472K| 1480 (1)|
| 2 | INDEX FULL SCAN | IND_TEST_OWNER | 51984 | | 123 (2)|
———————————————————————————–

index_combine會是and_equal的很好的替代者,隨著and_equal的退出,index_combine將更多得被我們看到。

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

相關文章