我正在尝试优化一组针对包括此视图在内的许多表的存储过程。观点是这样的:
我们有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时,问题也不存在(我有一个解决方法,但它并不理想。)。有没有办法让优化器首先检索数组值并将它们用作访问表时的谓词?还是重组视图来实现这一目标的好方法?
答案 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)