【发布时间】:2017-12-15 13:39:12
【问题描述】:
我有一个用 PL/SQL (Oracle 11.2g) 开发的外部 API,用于我的模块 SQL 语句。这是一个极其简化的例子:
select *
from (select column_value c from table(api_pkg.function(param1, param2))) t1
join table2 t2
on t2.pkc = t1.c
...
其中 table2.pkc 是此类表的 PK。问题是优化器不使用table2索引,查询性能很低。
如果我创建一个表
create table tmp_result as
select column_value c from table(api_pkg.function(param1, param2))
我在第一个查询中使用它,优化器使用 table2 索引
select *
from tmp_result t1
join table2 t2
on t2.pkc = t1.c
而且性能很棒。可以合理地认为,由于 Oracle 不知道函数将返回的行数,因此无法正确优化查询。
原始查询连接了 23 个表,而我很少有其他表使用这种方法并具有良好的执行计划,因此我不愿意添加提示来强制执行正确的执行计划。相反,我可以强制优化器首先找出函数返回的行数,然后生成计划吗?或者,当然还有其他方法?
到目前为止,我尝试了http://www.dba-oracle.com/t_materialize_sql_hint.htm,但没有成功,也无法强制使用带有提示的特定索引。
【问题讨论】:
-
您的函数通常可能返回多少行?它可能有很大的不同(即 1 行与 100 万行,具体取决于参数),还是大致相似?如果是后者,那么您可以考虑使用基数提示来说明预期的行数。它不必完全准确 - 例如,如果您返回 3000 行,则 1000 可能是一个足够好的“猜测”,但如果您期望 100 万行而您实际上得到 10 行,那么您可能不会得到最好的计划。
-
@Daniel Gutierrez - 您是否尝试在查询中使用索引提示?
/*+ index(t2 t2_idex_name) */之类的东西...应该紧跟在SELECT关键字之后。 -
您可以查看
ASSOCIATE STATISTICS将扩展统计信息应用于函数oracle-developer.net/display.php?id=426 -
其实同站的这篇文章可能更适合你的场景:setting cardinality for pipelined and table functions
-
是的,成本会随着动态采样而变化。所以呢?我从不看它。
标签: plsql oracle11g query-optimization