【问题标题】:Oracle Stored Procedure execution plan in case of IF ELSEIF ELSE 情况下的 Oracle 存储过程执行计划
【发布时间】:2016-09-28 05:49:56
【问题描述】:

我有一个问题,如果存储过程的执行计划具有 IF ELSE 语句,其中基于 IN 参数的值执行 IF 或 ELSE 块并且块中的查询获取相同的值,如何创建它来自相同的表,但在 where 子句中具有不同的列。

据我所知,每个存储过程只有一个执行计划。如果 Java 应用程序使用普通 JDBC 调用存储过程,则在第一次调用该过程时会创建执行计划,并且执行的 block(IF) 用于创建执行计划。

下次执行 ELSE 块时,它使用相同的执行计划,因此执行会很慢。

我问这个问题是因为我正在调用类似的存储过程,并且执行时间根据我传递的值和执行的块有很大的不同。

如果是这种情况,可以采取哪些措施来提高性能。是否应该编写一个单独的过程而不是使用 IF ELSE。

PFB存储过程代码:

PACKAGE         COP00134_006_1 AS
    TYPE t_cur_type IS REF CURSOR;
    PROCEDURE GetConsignmentDetails(
      sPInputList     IN VARCHAR2,
      sPInputType     IN VARCHAR2,
      cPCon           OUT t_cur_type,
      cPStatus        OUT t_cur_type,
      sPError         OUT VARCHAR2);
END COP00134_006_1;

实施:

PACKAGE BODY         COP00134_006_1 AS
    PROCEDURE GetConsignmentDetails(
      sPInputList     IN VARCHAR2,
      sPInputType     IN VARCHAR2,
      cPCon           OUT t_cur_type,
      cPStatus        OUT t_cur_type,
      sPError         OUT VARCHAR2)
    IS
    BEGIN
        sPError := '0';
        IF sPInputType = 'CON' THEN
         OPEN cPCon FOR
           SELECT 
                    con_id
                   ,con_legacy_id
                   ,con_create_td
                   ,con_pickup_lt
                   ,con_deliv_due_lt
                   ,CON_DELIV_END_LT
                   ,SRP_ID_AREA_DEST
                   ,CON_CLNT_REF_TX
                   ,BUL_CSYS_ID_ORIG
                   ,BUL_ID_ORIG
                   ,BUL_NM_ORIG
                   ,BUL_NM_DEST
                   ,cpn_oa_town_nm_r
                   ,cpn_oa_town_nm_d
                   ,cou_iso_id_orig
                   ,Cou_Nm_Orig
                   ,cou_iso_id_dest
                   ,Cou_Nm_Dest
                   ,PCE_QT
                   ,DUPLICATES
                   ,COS_SIGN_NM FROM (
             SELECT  /*+ cardinality (b 3) */ 
                    co.con_id
                   ,co.con_legacy_id
                   ,co.con_create_td
                   ,co.con_pickup_lt
                   ,co.con_deliv_due_lt
                   ,co.CON_DELIV_END_LT
                   ,co.SRP_ID_AREA_DEST
                   ,co.CON_CLNT_REF_TX
                   ,co.BUL_CSYS_ID_ORIG
                   ,blOrig.BUL_ID as BUL_ID_ORIG
                   ,blOrig.BUL_NM as BUL_NM_ORIG
                   ,blDest.BUL_NM as BUL_NM_DEST
                   ,cnr.cpn_oa_town_nm as cpn_oa_town_nm_r
                   ,cnd.cpn_oa_town_nm as cpn_oa_town_nm_d
                   ,co.cou_iso_id_orig
                   ,cuOrig.Cou_nm as Cou_Nm_Orig
                   ,co.cou_iso_id_dest
                   ,cuDest.Cou_nm as Cou_Nm_Dest
                   ,(select count(*) from CORPCV01 PC WHERE PC.CON_ID = CO.CON_ID) PCE_QT
                   ,CASE WHEN COUNT(*) OVER(PARTITION BY CON_LEGACY_ID) > 1 THEN 'TRUE' ELSE 'FALSE' END AS DUPLICATES
                   ,cs.COS_SIGN_NM, ROW_NUMBER() OVER(PARTITION BY CS.CON_ID ORDER BY COS_EVENT_TD) SEQ_NR
               FROM corcov01 co
              INNER JOIN corcnv01 cnr
                 ON cnr.con_id = co.con_id
                AND cnr.cpn_type_cd = 'R'
               LEFT OUTER JOIN corcnv01 cnd
                 ON cnd.con_id = co.con_id
                AND cnd.cpn_type_cd = 'D'
              INNER JOIN ncrcuv01 cuOrig
                 ON cuOrig.COU_ISO_ID = co.COU_ISO_ID_ORIG
                AND TRUNC(CURRENT_DATE) BETWEEN cuOrig.COU_EFFECT_DT AND cuOrig.COU_EFFECT_TO_DT
              INNER JOIN ncrcuv01 cuDest
                 ON cuDest.COU_ISO_ID = co.COU_ISO_ID_DEST
                AND TRUNC(CURRENT_DATE) BETWEEN cuDest.COU_EFFECT_DT AND cuDest.COU_EFFECT_TO_DT
              LEFT OUTER JOIN ncrblv01 blOrig
                 ON blOrig.BUL_CSYS_ID = co.BUL_CSYS_ID_ORIG
                AND TRUNC(CURRENT_DATE) BETWEEN blOrig.BUL_EFFECT_DT AND blOrig.BUL_EFFECT_TO_DT
              LEFT OUTER JOIN ncrblv01 blDest
                 ON blDest.BUL_CSYS_ID = co.BUL_CSYS_ID_DEST
                AND TRUNC(CURRENT_DATE) BETWEEN blDest.BUL_EFFECT_DT AND blDest.BUL_EFFECT_TO_DT
              LEFT OUTER JOIN corcsv01 cs
                 ON co.con_id = cs.con_id 
                AND cs.cos_sign_nm is not null
                and cs.cos_delete_in = 'N'
               WHERE co.con_Legacy_Id IN ( select dataItem from TABLE(ZYADMIN.ZYP90008.GetListFromCSV(sPInputList)) b )
               )WHERE SEQ_NR = 1;
          OPEN cPStatus FOR
              SELECT csv.CON_ID AS CON_ID_COS
                    ,csv.XSF_ID
                    ,csv.XSS_ID
                    ,csv.XSG_ID
                    ,csv.XSD_ID
                    ,ndv.XSX_ID
                    ,ndv.xsd_customer_ds
                    ,BUL_CSYS_ID_OCC
                    ,nlv.BUL_NM as BUL_NM_OCC
                    ,csv.COS_EVENT_LT
                    ,ndv.XSD_SEVERITY_CD
                    ,qb.QLA_DS
                FROM corcsv01 csv 
               INNER JOIN corcov01 co
                  ON csv.con_id = co.con_id
               INNER JOIN ncrsdv01 ndv 
                  ON ndv.XSF_ID=csv.XSF_ID 
                 AND ndv.XSS_ID=csv.XSS_ID 
                 AND ndv.XSG_ID=csv.XSG_ID 
                 AND ndv.XSD_ID=csv.XSD_ID 
                 AND TRUNC(CURRENT_DATE) BETWEEN ndv.XSD_EFFECT_DT AND ndv.XSD_EFFECT_TO_DT 
               INNER JOIN ncrksv01 ks 
                  ON ndv.XSX_ID= ks.XSX_ID 
                 AND TRUNC(CURRENT_DATE) BETWEEN ks.SKT_EFFECT_DT AND ks.SKT_EFFECT_TO_DT 
                 AND ks.SCA_ID = 'WEB'
               LEFT OUTER JOIN ncrqav01 qa
                 ON qa.XSX_ID = ndv.XSX_ID
                AND qa.APP_ID = 'EXCO'
                AND TRUNC(CURRENT_DATE) BETWEEN QAS_EFFECT_DT AND QAS_EFFECT_TO_DT
               LEFT OUTER JOIN ncrqbv01 qb
                 ON qa.QLA_ID = qb.QLA_ID
                AND qa.APP_ID = qb.APP_ID
                AND TRUNC(CURRENT_DATE) BETWEEN QLA_EFFECT_DT AND QLA_EFFECT_TO_DT
               INNER JOIN ncrblv01 nlv 
                  ON nlv.BUL_CSYS_ID=csv.BUL_CSYS_ID_OCC 
                 AND TRUNC(CURRENT_DATE)BETWEEN nlv.BUL_EFFECT_DT AND nlv.BUL_EFFECT_TO_DT 
               WHERE co.con_Legacy_Id IN ( select dataItem from TABLE(ZYADMIN.ZYP90008.GetListFromCSV(sPInputList)) b );
        ELSE
         OPEN cPCon FOR
                    SELECT 
                    con_id
                   ,con_legacy_id
                   ,con_create_td
                   ,con_pickup_lt
                   ,con_deliv_due_lt
                   ,CON_DELIV_END_LT
                   ,SRP_ID_AREA_DEST
                   ,CON_CLNT_REF_TX
                   ,BUL_CSYS_ID_ORIG
                   ,BUL_ID_ORIG
                   ,BUL_NM_ORIG
                   ,BUL_NM_DEST
                   ,cpn_oa_town_nm_r
                   ,cpn_oa_town_nm_d
                   ,cou_iso_id_orig
                   ,Cou_Nm_Orig
                   ,cou_iso_id_dest
                   ,Cou_Nm_Dest
                   ,PCE_QT
                   ,DUPLICATES
                   ,COS_SIGN_NM FROM (
             SELECT  /*+ cardinality (b 3) */ 
                    co.con_id
                   ,co.con_legacy_id
                   ,co.con_create_td
                   ,co.con_pickup_lt
                   ,co.con_deliv_due_lt
                   ,co.CON_DELIV_END_LT
                   ,co.SRP_ID_AREA_DEST
                   ,co.CON_CLNT_REF_TX
                   ,co.BUL_CSYS_ID_ORIG
                   ,blOrig.BUL_ID as BUL_ID_ORIG
                   ,blOrig.BUL_NM as BUL_NM_ORIG
                   ,blDest.BUL_NM as BUL_NM_DEST
                   ,cnr.cpn_oa_town_nm as cpn_oa_town_nm_r
                   ,cnd.cpn_oa_town_nm as cpn_oa_town_nm_d
                   ,co.cou_iso_id_orig
                   ,cuOrig.Cou_nm as Cou_Nm_Orig
                   ,co.cou_iso_id_dest
                   ,cuDest.Cou_nm as Cou_Nm_Dest
                   ,(select count(*) from CORPCV01 PC WHERE PC.CON_ID = CO.CON_ID) PCE_QT
                   ,'FALSE' AS DUPLICATES
                   ,cs.COS_SIGN_NM, ROW_NUMBER() OVER(PARTITION BY CS.CON_ID ORDER BY COS_EVENT_TD) SEQ_NR
               FROM corcov01 co
              INNER JOIN corcnv01 cnr
                 ON cnr.con_id = co.con_id
                AND cnr.cpn_type_cd = 'R'
               LEFT OUTER JOIN corcnv01 cnd
                 ON cnd.con_id = co.con_id
                AND cnd.cpn_type_cd = 'D'
              INNER JOIN ncrcuv01 cuOrig
                 ON cuOrig.COU_ISO_ID = co.COU_ISO_ID_ORIG
                AND TRUNC(CURRENT_DATE) BETWEEN cuOrig.COU_EFFECT_DT AND cuOrig.COU_EFFECT_TO_DT
              INNER JOIN ncrcuv01 cuDest
                 ON cuDest.COU_ISO_ID = co.COU_ISO_ID_DEST
                AND TRUNC(CURRENT_DATE) BETWEEN cuDest.COU_EFFECT_DT AND cuDest.COU_EFFECT_TO_DT
              LEFT OUTER JOIN ncrblv01 blOrig
                 ON blOrig.BUL_CSYS_ID = co.BUL_CSYS_ID_ORIG
                AND TRUNC(CURRENT_DATE) BETWEEN blOrig.BUL_EFFECT_DT AND blOrig.BUL_EFFECT_TO_DT
              LEFT OUTER JOIN ncrblv01 blDest
                 ON blDest.BUL_CSYS_ID = co.BUL_CSYS_ID_DEST
                AND TRUNC(CURRENT_DATE) BETWEEN blDest.BUL_EFFECT_DT AND blDest.BUL_EFFECT_TO_DT
              LEFT OUTER JOIN corcsv01 cs
                 ON co.con_id = cs.con_id 
                AND cs.cos_sign_nm is not null
                and cs.cos_delete_in = 'N'
               WHERE co.CON_CLNT_REF_CR IN ( select dataItem from TABLE(ZYADMIN.ZYP90008.GetListFromCSV(sPInputList)) b )
               )WHERE SEQ_NR = 1;
          OPEN cPStatus FOR
              SELECT csv.CON_ID AS CON_ID_COS
                    ,csv.XSF_ID
                    ,csv.XSS_ID
                    ,csv.XSG_ID
                    ,csv.XSD_ID
                    ,ndv.XSX_ID
                    ,ndv.xsd_customer_ds
                    ,BUL_CSYS_ID_OCC
                    ,nlv.BUL_NM as BUL_NM_OCC
                    ,csv.COS_EVENT_LT
                    ,ndv.XSD_SEVERITY_CD
                    ,qb.QLA_DS
                FROM corcsv01 csv 
               INNER JOIN corcov01 co
                  ON csv.con_id = co.con_id
               INNER JOIN ncrsdv01 ndv 
                  ON ndv.XSF_ID=csv.XSF_ID 
                 AND ndv.XSS_ID=csv.XSS_ID 
                 AND ndv.XSG_ID=csv.XSG_ID 
                 AND ndv.XSD_ID=csv.XSD_ID 
                 AND TRUNC(CURRENT_DATE) BETWEEN ndv.XSD_EFFECT_DT AND ndv.XSD_EFFECT_TO_DT 
               INNER JOIN ncrksv01 ks 
                  ON ndv.XSX_ID= ks.XSX_ID 
                 AND TRUNC(CURRENT_DATE) BETWEEN ks.SKT_EFFECT_DT AND ks.SKT_EFFECT_TO_DT 
                 AND ks.SCA_ID = 'WEB'
               LEFT OUTER JOIN ncrqav01 qa
                 ON qa.XSX_ID = ndv.XSX_ID
                AND qa.APP_ID = 'EXCO'
                AND TRUNC(CURRENT_DATE) BETWEEN QAS_EFFECT_DT AND QAS_EFFECT_TO_DT
               LEFT OUTER JOIN ncrqbv01 qb
                 ON qa.QLA_ID = qb.QLA_ID
                AND qa.APP_ID = qb.APP_ID
                AND TRUNC(CURRENT_DATE) BETWEEN QLA_EFFECT_DT AND QLA_EFFECT_TO_DT
               INNER JOIN ncrblv01 nlv 
                  ON nlv.BUL_CSYS_ID=csv.BUL_CSYS_ID_OCC 
                 AND TRUNC(CURRENT_DATE)BETWEEN nlv.BUL_EFFECT_DT AND nlv.BUL_EFFECT_TO_DT 
               WHERE co.CON_CLNT_REF_CR IN ( select dataItem from TABLE(ZYADMIN.ZYP90008.GetListFromCSV(sPInputList)) b );
        END IF;
    EXCEPTION
        WHEN OTHERS THEN
          sPError := '1' ||' '||SQLCODE||' '||SUBSTR(SQLERRM, 1, 200);
    END;
END COP00134_006_1;

问题在于在 ELSE 部分执行的查询。 正如 cmets 中提到的,我已经单独运行了相同的查询,它们在不到一秒的时间内执行,而当相同的数据传递给过程时,需要一分钟以上。我无法运行分析器,因为我没有数据库访问权限,并且向 DBA 询问相同的过程需要一个多星期的时间,我需要尽快解决这个问题

【问题讨论】:

  • AFAI,是的,如果您在通过 jdbc 从数据库检索数据时遇到性能问题,您应该这样做。
  • SQL 查询有执行计划,而不是存储过程(或任何 PL/SQL 代码块)。因此,将在您的存储过程中针对每个查询考虑执行计划。您不会像您描述的那样遇到问题。
  • @cihanseven - 不知道你的意思。只要配置正确,JDBC 就可以发挥出色的性能。
  • @APC 我没有提到性能问题与 JDBC 有关。它工作正常,没问题。我打算注意在存储过程上浪费时间。但我想是误解了,没问题兄弟:)

标签: oracle performance stored-procedures jdbc


【解决方案1】:

Oracle 为查询而不是存储过程构建执行计划。因此,存储过程中的每个查询都有自己的执行计划。你这样说你的查询:

"where 子句中有不同的列"

不同的列意味着不同的访问路径:这可能会转化为不同的索引使用、不同的磁盘读取活动、可能不同的数据量。因此,根据采用 IF...ELSE 的哪个分支来体验不同的性能也就不足为奇了。拥有单独的过程不会改变底层查询的性能。

要检查差异,请为每个单独的查询运行 EXPLAIN PLAN。 Find out more。您需要将语句剪切并粘贴到 SQL 工作表(或您用于处理 SQL 的任何工具)中。


如果您认为问题出在存储过程中,那么您应该使用 PL/SQL 分析器调查时间的去向。 Find out more。如果尚未安装,您可能需要 DBA 来安装它。


“当在存储过程中使用相同的值和相同的数据执行相同的查询时,需要 60 多秒”

你一直在谈论经过的时间。你是如何测量这些的?你在测量什么?时间都去哪儿了?这不是第一次指责数据库性能不佳,而真正的罪魁祸首是糟糕的 JDBC 配置的不良网络连接。

【讨论】:

  • 我已经为单个查询运行了解释计划,解释计划看起来不错。此外,查询在不到 0.5 秒内执行。但是,当在存储过程中使用相同的值和相同的数据执行相同的查询时,需要 60 多秒。
  • 我们已经达到了 StackOverflow 上的人们可以使用您迄今为止提供的信息的极限。诊断需要线索:它需要查看代码、原始数据、样本输入和输出、解释计划和配置文件。
  • 我已经添加了存储过程代码。希望我能有所收获。
猜你喜欢
  • 2015-05-22
  • 1970-01-01
  • 2018-10-20
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 2010-12-13
  • 2022-10-05
  • 1970-01-01
相关资源
最近更新 更多