为什么Oracle SQL Optimizer忽略了此视图的索引谓词?

时间:2014-01-02 22:13:04

标签: sql oracle view indexing

我正在尝试优化一组针对包括此视图在内的许多表的存储过程。观点是这样的:

我们有TBL_A(id,hist_date,hist_type,other_columns)有两种类型的行:hist_type'O'与hist_type'N'。视图self将表A连接到自身,并将N行转换为相应的O行。如果O行不存在N行,则重复O行值。像这样:

CREATE OR REPLACE FORCE VIEW V_A (id, hist_date, hist_type, other_columns_o, other_columns_n)
select 
o.id, o.hist_date, o.hist_type, 
o.other_columns as other_columns_o,
case when n.id is not null then n.other_columns else o.other_columns end as other_columns_n
from
TBL_A o left outer join TBL_A n
on o.id=n.id and o.hist_date=n.hist_date and n.hist_type = 'N'
where o.hist_type = 'O';

TBL_A在:(id,hist_date,hist_type)上有唯一索引。它还有一个唯一索引:(hist_date,id,hist_type),这是主键。

以下查询存在争议(在存储过程中,x声明为TYPE_TABLE_OF_NUMBER):

select b.id BULK COLLECT into x from TBL_B b where b.parent_id = input_id;

select v.id from v_a v
where v.id in (select column_value from table(x))
and   v.hist_date = input_date
and   v.status_new = 'CLOSED';

此查询在访问TBL_A时忽略id列上的索引,而是使用日期进行范围扫描以获取日期的所有行。 然后它使用数组中的值过滤设置。但是,如果我只是将id列表作为数字列表给出,那么优化器就可以使用索引了:

select v.id from v_a v
where v.id in (123, 234, 345, 456, 567, 678, 789)
and   v.hist_date = input_date
and   v.status_new = 'CLOSED';

当直接针对TBL_A时,问题也不存在(我有一个解决方法,但它并不理想。)。有没有办法让优化器首先检索数组值并将它们用作访问表时的谓词?还是重组视图来实现这一目标的好方法?

1 个答案:

答案 0 :(得分:2)

Oracle不使用索引,因为它假设select column_value from table(x)返回8168行。

索引可以更快地检索少量数据。在某些时候,扫描整个表比反复遍历索引树更快。

估计常规SQL语句的基数是很困难的。为程序代码创建准确的估计几乎是不可能的。但是我不知道他们在哪里提出了8168.表函数通常与数据仓库中的流水线函数一起使用,大量的数据是有意义的。

Dynamic sampling可以生成更准确的估算值,并可能生成将使用该索引的计划。

以下是基数估算不佳的示例:

create or replace type type_table_of_number as table of number;

explain plan for
select * from table(type_table_of_number(1,2,3,4,5,6,7));
select * from table(dbms_xplan.display(format => '-cost -bytes'));

Plan hash value: 1748000095

-------------------------------------------------------------------------
| Id  | Operation                             | Name | Rows  | Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |      |  8168 | 00:00:01 |
|   1 |  COLLECTION ITERATOR CONSTRUCTOR FETCH|      |  8168 | 00:00:01 |
-------------------------------------------------------------------------

以下是修复方法:

explain plan for select /*+ dynamic_sampling(2) */ *
                 from table(type_table_of_number(1,2,3,4,5,6,7));
select * from table(dbms_xplan.display(format => '-cost -bytes'));

Plan hash value: 1748000095

-------------------------------------------------------------------------
| Id  | Operation                             | Name | Rows  | Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |      |     7 | 00:00:01 |
|   1 |  COLLECTION ITERATOR CONSTRUCTOR FETCH|      |     7 | 00:00:01 |
-------------------------------------------------------------------------

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)