日期:2014-05-17  浏览次数:21135 次

频繁的调用select大表的Function,比起直接包在sql中select,效能如何?
为了判断select的记录是否符合要求,会在select的时候传入参数返回一个flag,判断是否是合法的
function的内容如下
SQL code

CREATE OR REPLACE FUNCTION FN_CANCEL_WHITE(BarCode    IN VARCHAR2,
                                           CREATEDATE IN DATE)
  RETURN VARCHAR2 IS
  ABEXISTS VARCHAR2(2);
BEGIN
    SELECT CASE
           WHEN COUNT(LOT_2) = 0 THEN
            'N'
           ELSE
            'Y'
         END
    INTO ABEXISTS
    FROM (SELECT H.LOT_2
            FROM ZZ_CANCEL_OPERATION_SUMMARY H
           WHERE H.LOT_2=BarCode
             AND H.CREATE_DATE > CREATEDATE
             AND H.APPLICATION_NAME = 'PartCutRetreatWorkData'
           ORDER BY CREATE_DATE ASC)
   WHERE ROWNUM = 1;

  RETURN ABEXISTS;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN 0;
END;



调用的SQL
SQL code

SELECT fn_cancel_white(Z.LOT2,Z.CREATE_DATE) FLAG FROM ZZ_WHITEPMSTORAGE_SUMMARY Z 



Function中用到的表记录大概两万多,且都是主键扫描。

不晓得在频繁的调用function的时候,频繁的select操作是否影响性能,比起直接在sql中直接加语句中加条件判断,如下:
SQL code

WHERE NOT EXISTS (SELECT * 
  FROM ZZ_CANCEL_OPERATION_SUMMARY H
   WHERE H.LOT_2= Z.LOT2
   AND H.CREATE_DATE > Z.CREATE_DATE
   AND H.APPLICATION_NAME = 'PartCutRetreatWorkData')



哪种方法效率更高?为什么?
若是function中调用的表记录数是亿级别的,是否应避免这样使用?

------解决方案--------------------
首先:你的函数写的有毛病,排序是没有必要加的
原因:你的目的无非是想看asc排序之后有没有第一条记录,有就是Y 没有就是N,我实在想不出 排序 和 不排序 对结果有什么影响,况且排序是很费“体力”的事情。

其次:where条件中用到not 往往都是很费力的事情,因为需要全表扫描才能知道到底是不是真正的 not,这很好理解,因为只要有一条记录扫描不到,那么就有可能存在 非 not 的情况。

至于具体执行效率,还要关注执行计划,做具体分析。
不过根据你的业务逻辑从直观上讲,个人比较倾向于:第一种fuction的方式。


------解决方案--------------------
效率基本没差别。
2w条的记录对数据库是小case了。
order by和rownum也没什么问题。
------解决方案--------------------

如果你是联机应用,一次只判断很少(相对于表中总数据而言)记录的状态,用你原来的方法基本正确.另外把二楼的第一条建议用上.

如果你是批量任务,要判断ZZ_WHITEPMSTORAGE_SUMMARY Z中多数记录的状态,建议你用语句的方式,能减少sql引起于plsql引擎之间切换,而且func中外部语句执行计划不能连接优化.
用not 效率比较低,可以换成关联(你可以用left jion)
SELECT decode(nvl(H.LOT_2,0),0,'N','Y') flag
示例
FROM ZZ_WHITEPMSTORAGE_SUMMARY Z,
ZZ_CANCEL_OPERATION_SUMMARY H
WHERE Z.LOT2 =H.LOT_2(+)
 AND Z.CREATE_DATE < H.CREATE_DATE(+)
 AND H.APPLICATION_NAME(+) = 'PartCutRetreatWorkData'

最后如果你的数据只有千八百地,就不要纠结方法了,差别不大.
------解决方案--------------------
探讨
引用:

首先:你的函数写的有毛病,排序是没有必要加的
原因:你的目的无非是想看asc排序之后有没有第一条记录,有就是Y 没有就是N,我实在想不出 排序 和 不排序 对结果有什么影响,况且排序是很费“体力”的事情。

其次:where条件中用到not 往往都是很费力的事情,因为需要全表扫描才能知道到底是不是真正的 not,这很好理解,因为只要有一条记……