INLIST ITERATOR :迭代查询,lnlist 里面几个值就要扫描几次。
CONCATENATION :联合返回二个或多个行集。
官方文档:
When the Optimizer Uses IN-List Iterators The optimizer uses an IN-list iterator when an IN clause is specified with values, and the optimizer finds a selective index for that column. If there are multiple OR clauses using the same index, then the optimizer chooses this operation rather than CONCATENATION or UNION ALL, because it is more efficient.
翻译大致的意思是,如果用的or条件使用了相同的索引,优化器会更趋向于选择IN-list iterator,而不是CONCATENATION或UNION ALL。
iterator里面每次执行的代码都一样只是变量值不同,CONCATENATION里面的代码可能不同(比如 A=0 OR B=0)只是最终结果可以合并。
----------------------------------------------------------开始试验--------------------------------------------------------------
create table test as select * from dba_objects;
create index I_OBJECT_ID on TEST (OBJECT_ID);
create index I_OBJECT_NAME on TEST (OBJECT_NAME);
SQL> select /*+gather_plan_statistics*/ count(1) from test where
2 object_id in(20,30,40,50,60);
COUNT(1)
----------
5
SQL> SELECT * FROM table(dbms_xplan.display_cursor(null,null,'iostats last'));
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 10 |
| 2 | INLIST ITERATOR | | 1 | | 5 |00:00:00.01 | 10 |
|* 3 | INDEX RANGE SCAN| I_OBJECT_ID | 5 | 5 | 5 |00:00:00.01 | 10 | ---有几个值就迭代几次
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access(("OBJECT_ID"=20 OR "OBJECT_ID"=30 OR "OBJECT_ID"=40 OR "OBJECT_ID"=50
OR "OBJECT_ID"=60))
SQL> select /*+gather_plan_statistics*/ count(1) from test a
2 where a.object_id=20 or a.object_name='ICOL$';
COUNT(1)
----------
1
SQL> SELECT * FROM table(dbms_xplan.display_cursor(null,null,'iostats last'));
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 5 |
| 2 | BITMAP CONVERSION COUNT | | 1 | 3 | 1 |00:00:00.01 | 5 |
| 3 | BITMAP OR | | 1 | | 1 |00:00:00.01 | 5 |
| 4 | BITMAP CONVERSION FROM ROWIDS| | 1 | | 1 |00:00:00.01 | 3 |
|* 5 | INDEX RANGE SCAN | I_OBJECT_NAME | 1 | | 1 |00:00:00.01 | 3 |
| 6 | BITMAP CONVERSION FROM ROWIDS| | 1 | | 1 |00:00:00.01 | 2 |
|* 7 | INDEX RANGE SCAN | I_OBJECT_ID | 1 | | 1 |00:00:00.01 | 2 |
------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("A"."OBJECT_NAME"='ICOL$')
7 - access("A"."OBJECT_ID"=20)
SQL> select /*+gather_plan_statistics use_concat*/ count(1) from test a
2 where a.object_id=20 or a.object_name='ICOL$';
COUNT(1)
----------
1
SQL> SELECT * FROM table(dbms_xplan.display_cursor(null,null,'iostats last'));
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 7 |
| 2 | CONCATENATION | | 1 | | 1 |00:00:00.01 | 7 |
| 3 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 1 | 1 |00:00:00.01 | 3 |
|* 4 | INDEX RANGE SCAN | I_OBJECT_ID | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 5 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 2 | 0 |00:00:00.01 | 4 |
|* 6 | INDEX RANGE SCAN | I_OBJECT_NAME | 1 | 2 | 1 |00:00:00.01 | 3 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OBJECT_ID"=20)
5 - filter(LNNVL("A"."OBJECT_ID"=20))
6 - access("A"."OBJECT_NAME"='ICOL$')