是否可以使用oracle提示将(pl/sql)条件推迟到最后?

是否可以使用oracle提示将(pl/sql)条件推迟到最后?,sql,oracle11g,Sql,Oracle11g,我试图优化包含pl/sql函数的select(实际上是pl/sql代码中的游标) select * from mytable t,mytable2 t2... where t.thing = 'XXX' ... lots more joins and sql predicate on various columns and myplsqlfunction(t.val) = 'X' myplsqlfunction()非常昂贵,但只适用于其他条件中可管理的一小部分。 问题是Oracle似乎

我试图优化包含pl/sql函数的select(实际上是pl/sql代码中的游标)

    select * from mytable t,mytable2 t2...
where t.thing = 'XXX'
... lots more joins and sql predicate on various columns
and myplsqlfunction(t.val) = 'X'
myplsqlfunction()非常昂贵,但只适用于其他条件中可管理的一小部分。 问题是Oracle似乎在评估myplsqlfunction()时使用的数据比理想的数据多。 我的证据是,如果我将上述内容改写为

select * from (
        select * from mytable t,mytable2 t2...
    where t.thing = 'XXX'
    ... lots more joins and sql predicate on various columns
) where myplsqlfunction(t.val) = 'X'
或pl/sql作为:

begin
for t in ( select * from mytable t,mytable2 t2...
        where t.thing = 'XXX'
        ... lots more joins and sql predicate on various columns ) loop
   if myplsqlfunction(t.val) = 'X' then
       -- process the desired subset
   end if;
end loop;
end;
性能好一个数量级


我很乐意使用上述两种习惯用法中的任何一种来重新构造有问题的代码,但如果有更简单的方法让Oracle optimizer为我执行此操作,我将非常高兴。

您可以指定一系列提示来强制执行特定计划。但几乎可以肯定的是,这比重组代码更痛苦


我想你真正想做的是。如果您告诉Oracle该函数的选择性比优化器猜测的要低,或者(更有可能)您为该函数的CPU或I/O成本提供了较高的值,则会导致优化器尝试尽可能少地调用该函数。oracle-developer.net文章介绍了如何为成本选择合理正确的值(或者进一步介绍了如何随着函数调用成本的变化使这些统计信息随时间而变化)。您可能可以通过设置疯狂的高成本来解决眼前的问题,但您可能希望努力设置准确的值,以便为优化器提供尽可能准确的信息。将成本设置得太高或太低往往会导致某些查询集执行愚蠢的操作。

您可以使用WITH子句首先计算所有连接条件,并获得可管理的数据子集。然后,可以在数据子集上使用pl/sql函数。但这取决于音量,你还是可以试试这个。任何问题请告诉我。

您可以使用CTE,如:

WITH X as
( select /*+ MATERIALIZE */ * from mytable t,mytable2 t2...
    where t.thing = 'XXX'
    ... lots more joins and sql predicate on various columns
) 
SELECT * FROM X
where myplsqlfunction(t.val) = 'X';
注意materialize提示。CTE可以是内联的,也可以是物化的(进入临时表空间)

另一个选项是使用
NO\u PUSH\u PRED
hint。这通常是更好的解决方案(避免子查询的具体化),但需要一些调整

PS:您应该而不是从myplsqlfunction调用另一个SQL。此SQL可能会看到在查询启动后添加的数据,您可能会得到令人惊讶的结果

您还可以将函数声明为RESULT_CACHE,以强制Oracle记住来自函数的返回值(如果适用),即可能的函数参数值的数量相当小


正如Justin所描述的,最好的解决方案可能是将统计数据关联起来。

当您重新构造代码时,您还应该开始使用显式
JOIN
语法,而不是隐式联接。优化器没有义务在应用其他谓词之前评估CTE,而不是评估内联视图,而不是将谓词推入内联视图。谢谢Justin。事实上,重组并没有那么困难,至少让决策变得明确而持久。虽然定义非默认统计数据很有趣,但我担心它们对其他开发人员缺乏可见性。因此,我将进行重组