Oracle :=插入总计数+行计数; 如果(行)计数为0,则 ERRMSG:='**错误:'| |错误| | |'阶段记录未正确插入到已处理的表'; 引发应用程序错误(-20001,ErrMsg); 如果结束; 例外 当其他人 提升 终止 我的XML只有一个rp_sendRow元素,最多可以包含2000个rp_sendRow元素 0123 022399190 0.01 符合事实的 2013-04-19 146.51 13 0 0 0 0 0 0 0 0 13 2015-06-16 09:12:21

Oracle :=插入总计数+行计数; 如果(行)计数为0,则 ERRMSG:='**错误:'| |错误| | |'阶段记录未正确插入到已处理的表'; 引发应用程序错误(-20001,ErrMsg); 如果结束; 例外 当其他人 提升 终止 我的XML只有一个rp_sendRow元素,最多可以包含2000个rp_sendRow元素 0123 022399190 0.01 符合事实的 2013-04-19 146.51 13 0 0 0 0 0 0 0 0 13 2015-06-16 09:12:21,oracle,xmltype,Oracle,Xmltype,根据OTN和AskTom,问题在于PLSQL的版本及其在每个版本中的解析方式 在PL/SQL 11.2.0.4之前的版本中,解析依赖于存储类型,效率低下 在11.2.0.4之前的版本中,Oracle使用基于内存中类似DOM的XML文档表示的函数求值。这就是性能下降的原因。如果在参数声明中添加NOCOPY,要求编译器通过引用而不是通过值传递,会发生什么情况?@JustinCave unfortunaely,我不能为IN-param添加NOCOPY。如果我添加它,会引发编译错误。尝试使用dbms

根据OTN和AskTom,问题在于PLSQL的版本及其在每个版本中的解析方式

在PL/SQL 11.2.0.4之前的版本中,解析依赖于存储类型,效率低下


在11.2.0.4之前的版本中,Oracle使用基于内存中类似DOM的XML文档表示的函数求值。这就是性能下降的原因。

如果在参数声明中添加
NOCOPY
,要求编译器通过引用而不是通过值传递,会发生什么情况?@JustinCave unfortunaely,我不能为IN-param添加NOCOPY。如果我添加它,会引发编译错误。尝试使用dbms_profiler。也许它会显示您在哪里花费了大部分时间我们测试了这一点,并确认作为param传递的XML的执行计划与根据OTN注释从表中获取XML的执行计划不同
/*
This one is taking .15 seconds to process an XML with about 2000 rp_sendRow elements
*/
DECLARE
  CURSOR NewStage IS
        SELECT * 
        FROM STAGE_TBL
        WHERE  status = 'N' 
        ORDER BY PUT_TIME ASC;
      SUBTYPE rt_NewStage IS NewStage % rowtype;

  ROW_COUNT           INTEGER := 0;   -- Return value from calling the procedure
  READ_COUNT          INTEGER := 0;   -- Number of rows read from the stage table
  INSERT_COUNT_TOTAL  INTEGER := 0;   -- Number of Inserts Inven records
  ERROR_COUNT         INTEGER := 0;   -- Number of Inven inserts that did inserted more then 1 row in Inven
  PROCESS_STATUS      STATUS.MmsStatus;
  STATUS_DESCRIPTION  STATUS.MmsStatusReason;
  ERRMSG              VARCHAR2(500);

PROCEDURE STAGE_TBL_PROCESS (IDDATA IN RAW, PROCESS_STATUS OUT VARCHAR2, STATUS_DESCRIPTION OUT VARCHAR2, ROW_COUNT OUT NUMBER) AS 
/*
  This procedure is to parse the XML from STAGE_TBL and populate the data from XML to PROCESSED_DATA_TBL table

  IN PARAMS
  ----------
  IDDATA              -   ID from STAGE_TBL
  xData                 -   XMLType field from XML_DOCUMENT of STAGE_TBL

  OUT PARAMS
  -----------
  PROCESS_STATUS        -   The STATUS of parsing and populating PROCESSED_DATA_TBL
  STATUS_DESCRIPTION    -   The description of the STATUS of parsing and populating PROCESSED_DATA_TBL
  ROW_COUNT             -   Number of rows inserted into PROCESSED_DATA_TBL
*/
BEGIN
     INSERT ALL INTO PROCESSED_DATA_TBL  
        (PD_ID,  
        STORE,  
        SALES_NBR,  
        UNIT_COST,  
        ST_FLAG,  
        ST_DATE,  
        ST,  
        START_QTY,  
        START_VALUE,  
        START_ON_ORDER,  
        HAND,  
        ORDERED,  
        COMMITED,  
        SALES,  
        RECEIVE,  
        VALUED,  
        ID_1,  
        ID_2,  
        ID_3,  
        UNIT_PRICE,  
        EFFECTIVE_DATE,  
        STATUS,  
        STATUS_DATE,  
        STATUS_REASON)  
        VALUES (IDDATA   
              ,store  
              ,SalesNo  
              ,UnitCost         
              ,StWac  
              ,StDt           
              ,St          
              ,StartQty           
              ,StartValue         
              ,StartOnOrder       
              ,Hand      
              ,Ordered     
              ,COMMITED      
              ,Sales       
              ,Rec      
              ,Valued    
              ,Id1            
              ,Id2            
              ,Id3            
              ,UnitPrice     
              ,to_Date(EffectiveDate||' '||EffectiveTime, 'YYYY-MM-DD HH24:MI:SS')  
              ,'N'      
              ,SYSDATE  
              ,'XML PROCESS INSERT')      
        WITH T AS 
        ( SELECT STG.XML_DOCUMENT FROM STAGE_TBL STG WHERE STG.ID = IDDATA)         
--      This is to parse and fetch the data from XML              
        SELECT E.* FROM T, XMLTABLE('rp_send/rp_sendRow' PASSING T.XML_DOCUMENT COLUMNS
                               store            VARCHAR(20) PATH 'store'   
                              ,SalesNo          VARCHAR(20) PATH 'sales'  
                              ,UnitCost         NUMBER      PATH 'cost'  
                              ,StWac            VARCHAR(20) PATH 'flag'  
                              ,StDt             DATE        PATH 'st-dt'  
                              ,St               NUMBER      PATH 'st'  
                              ,StartQty         NUMBER      PATH 'qty'  
                              ,StartValue       NUMBER      PATH 'value'  
                              ,StartOnOrder     NUMBER      PATH 'start-on-order'  
                              ,Hand             NUMBER      PATH 'hand'  
                              ,Ordered            NUMBER      PATH 'order'  
                              ,Commited           NUMBER      PATH 'commit'  
                              ,Sales            NUMBER      PATH 'sales'  
                              ,Rec              NUMBER      PATH 'rec'  
                              ,Valued            NUMBER      PATH 'val'  
                              ,Id1              VARCHAR(30) PATH 'id-1'  
                              ,Id2              VARCHAR(30) PATH 'id-2'  
                              ,Id3              VARCHAR(30) PATH 'id-3'  
                              ,UnitPrice        NUMBER      PATH 'unit-pr'  
                              ,EffectiveDate    VARCHAR(30) PATH 'eff-dt'  
                              ,EffectiveTime    VARCHAR(30) PATH 'eff-tm'  
        ) E;     
      ROW_COUNT           := SQL%ROWCOUNT;  -- Not the # of all the rows inserted. 
      PROCESS_STATUS      := STATUS.PROCESSED;
      IF ROW_COUNT < 1 THEN       -- The insert failed Row Count = 0  No exception thrown 
        PROCESS_STATUS      := STATUS.ERROR;
        STATUS_DESCRIPTION  := 'ERROR Did not insert into Pos Inventory. Reason Unknown';
      END IF;
      EXCEPTION
      WHEN OTHERS THEN
        ROW_COUNT           := 0;
        PROCESS_STATUS      := STATUS.ERROR;
        STATUS_DESCRIPTION  := 'SqlCode:' || SQLCODE || ' SqlErrMsg:' || SQLERRM;
END;


BEGIN
  DBMS_OUTPUT.enable(NULL);
  FOR A_NewStage IN NewStage
  LOOP
      READ_COUNT := READ_COUNT + 1;
      STAGE_TBL_PROCESS(A_NewStage.ID, PROCESS_STATUS, STATUS_DESCRIPTION, ROW_COUNT);
      INSERT_COUNT_TOTAL := INSERT_COUNT_TOTAL + ROW_COUNT;
      IF(ROW_COUNT <= 0 OR PROCESS_STATUS = STATUS.ERROR) THEN
          ERROR_COUNT := ERROR_COUNT + 1;
          UPDATE STAGE_TBL 
          SET status              = PROCESS_STATUS,
              status_DATE         = SYSDATE,
              status_DESCRIPTION  = STATUS_DESCRIPTION
          WHERE ID                  = A_NewStage.ID; 
        ELSE 
          UPDATE STAGE_TBL 
          SET status              = PROCESS_STATUS,
              status_DATE         = SYSDATE,
              status_DESCRIPTION  = STATUS_DESCRIPTION,
              SHRED_DT                = SYSDATE
          WHERE ID                  = A_NewStage.ID; 
        END IF; 
        COMMIT;
  END LOOP;
  COMMIT;
  IF ERROR_COUNT > 0 THEN
     ERRMSG := '** ERROR: ' || ERROR_COUNT || ' Stage records did not insert in to the Processed table correctly';
     RAISE_APPLICATION_ERROR(-20001,ErrMsg);  
  END IF;
    EXCEPTION 
      WHEN OTHERS THEN
          RAISE;
END ;

/*
This one is taking 10 seconds to process an XML with about 2000 rp_sendRow elements
*/
DECLARE
  CURSOR NewStage IS
        SELECT * 
        FROM STAGE_TBL
        WHERE  status = 'N' 
        ORDER BY PUT_TIME ASC;
      SUBTYPE rt_NewStage IS NewStage % rowtype;

  ROW_COUNT           INTEGER := 0;   -- Return value from calling the procedure
  READ_COUNT          INTEGER := 0;   -- Number of rows read from the stage table
  INSERT_COUNT_TOTAL  INTEGER := 0;   -- Number of Inserts Inven records
  ERROR_COUNT         INTEGER := 0;   -- Number of Inven inserts that did inserted more then 1 row in Inven
  PROCESS_STATUS      STATUS.MmsStatus;
  STATUS_DESCRIPTION  STATUS.MmsStatusReason;
  ERRMSG              VARCHAR2(500);

PROCEDURE STAGE_TBL_PROCESS (IDDATA IN RAW, xData IN STAGE_TBL.XML_DOCUMENT%TYPE, PROCESS_STATUS OUT VARCHAR2, STATUS_DESCRIPTION OUT VARCHAR2, ROW_COUNT   OUT NUMBER) AS 
/*
  This procedure is to parse the XML from STAGE_TBL and populate the data from XML to PROCESSED_DATA_TBL table

  IN PARAMS
  ----------
  IDDATA              -   ID from STAGE_TBL
  xData                 -   XMLType field from XML_DOCUMENT of STAGE_TBL

  OUT PARAMS
  -----------
  PROCESS_STATUS        -   The STATUS of parsing and populating PROCESSED_DATA_TBL
  STATUS_DESCRIPTION    -   The description of the STATUS of parsing and populating PROCESSED_DATA_TBL
  ROW_COUNT             -   Number of rows inserted into PROCESSED_DATA_TBL
*/
BEGIN
     INSERT ALL INTO PROCESSED_DATA_TBL  
        (PD_ID,  
        STORE,  
        SALES_NBR,  
        UNIT_COST,  
        ST_FLAG,  
        ST_DATE,  
        ST,  
        START_QTY,  
        START_VALUE,  
        START_ON_ORDER,  
        HAND,  
        ORDERED,  
        COMMITED,  
        SALES,  
        RECEIVE,  
        VALUED,  
        ID_1,  
        ID_2,  
        ID_3,  
        UNIT_PRICE,  
        EFFECTIVE_DATE,  
        STATUS,  
        STATUS_DATE,  
        STATUS_REASON)  
        VALUES (IDDATA   
              ,store  
              ,SalesNo  
              ,UnitCost         
              ,StWac  
              ,StDt           
              ,St          
              ,StartQty           
              ,StartValue         
              ,StartOnOrder       
              ,Hand      
              ,Ordered     
              ,COMMITED      
              ,Sales       
              ,Rec      
              ,Valued    
              ,Id1            
              ,Id2            
              ,Id3            
              ,UnitPrice     
              ,to_Date(EffectiveDate||' '||EffectiveTime, 'YYYY-MM-DD HH24:MI:SS')  
              ,'N'      
              ,SYSDATE  
              ,'XML PROCESS INSERT')      
--      This is to parse and fetch the data from XML              
        SELECT E.* FROM XMLTABLE('rp_send/rp_sendRow' PASSING xDATA COLUMNS
                               store            VARCHAR(20) PATH 'store'   
                              ,SalesNo          VARCHAR(20) PATH 'sales'  
                              ,UnitCost         NUMBER      PATH 'cost'  
                              ,StWac            VARCHAR(20) PATH 'flag'  
                              ,StDt             DATE        PATH 'st-dt'  
                              ,St               NUMBER      PATH 'st'  
                              ,StartQty         NUMBER      PATH 'qty'  
                              ,StartValue       NUMBER      PATH 'value'  
                              ,StartOnOrder     NUMBER      PATH 'start-on-order'  
                              ,Hand             NUMBER      PATH 'hand'  
                              ,Ordered            NUMBER      PATH 'order'  
                              ,Commited           NUMBER      PATH 'commit'  
                              ,Sales            NUMBER      PATH 'sales'  
                              ,Rec              NUMBER      PATH 'rec'  
                              ,Valued            NUMBER      PATH 'val'  
                              ,Id1              VARCHAR(30) PATH 'id-1'  
                              ,Id2              VARCHAR(30) PATH 'id-2'  
                              ,Id3              VARCHAR(30) PATH 'id-3'  
                              ,UnitPrice        NUMBER      PATH 'unit-pr'  
                              ,EffectiveDate    VARCHAR(30) PATH 'eff-dt'  
                              ,EffectiveTime    VARCHAR(30) PATH 'eff-tm'  
        ) E;     
      ROW_COUNT           := SQL%ROWCOUNT;  -- Not the # of all the rows inserted. 
      PROCESS_STATUS      := STATUS.PROCESSED;
      IF ROW_COUNT < 1 THEN       -- The insert failed Row Count = 0  No exception thrown 
        PROCESS_STATUS      := STATUS.ERROR;
        STATUS_DESCRIPTION  := 'ERROR Did not insert into Pos Inventory. Reason Unknown';
      END IF;
      EXCEPTION
      WHEN OTHERS THEN
        ROW_COUNT           := 0;
        PROCESS_STATUS      := STATUS.ERROR;
        STATUS_DESCRIPTION  := 'SqlCode:' || SQLCODE || ' SqlErrMsg:' || SQLERRM;
END;


BEGIN
  DBMS_OUTPUT.enable(NULL);
  FOR A_NewStage IN NewStage
  LOOP
      READ_COUNT := READ_COUNT + 1;
      STAGE_TBL_PROCESS(A_NewStage.ID, A_NewStage.XML_DOCUMENT, PROCESS_STATUS, STATUS_DESCRIPTION, ROW_COUNT);
      INSERT_COUNT_TOTAL := INSERT_COUNT_TOTAL + ROW_COUNT;
      IF(ROW_COUNT <= 0 OR PROCESS_STATUS = STATUS.ERROR) THEN
          ERROR_COUNT := ERROR_COUNT + 1;
          UPDATE STAGE_TBL 
          SET status              = PROCESS_STATUS,
              status_DATE         = SYSDATE,
              status_DESCRIPTION  = STATUS_DESCRIPTION
          WHERE ID                  = A_NewStage.ID; 
        ELSE 
          UPDATE STAGE_TBL 
          SET status              = PROCESS_STATUS,
              status_DATE         = SYSDATE,
              status_DESCRIPTION  = STATUS_DESCRIPTION,
              SHRED_DT                = SYSDATE
          WHERE ID                  = A_NewStage.ID; 
        END IF; 
        COMMIT;
  END LOOP;
  COMMIT;
  IF ERROR_COUNT > 0 THEN
     ERRMSG := '** ERROR: ' || ERROR_COUNT || ' Stage records did not insert in to the Processed table correctly';
     RAISE_APPLICATION_ERROR(-20001,ErrMsg);  
  END IF;
    EXCEPTION 
      WHEN OTHERS THEN
          RAISE;
END ;

My XML with just one rp_sendRow element, it can go upto 2000 rp_sendRow elements 
<?xml version = \"1.0\" encoding = \"UTF-8\"?>  
<rp_send xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">  
    <rp_sendRow>  
        <store>0123</store>  
        <sales>022399190</sales>  
        <cost>0.01</cost>  
        <flag>true</flag>  
        <st-dt>2013-04-19</st-dt>  
        <st>146.51</st>  
        <qty>13.0</qty>  
        <value>0.0</value>  
        <start-on-order>0.0</start-on-order>  
        <hand>0.0</hand>  
        <order>0.0</order>  
        <commit>0.0</commit>  
        <sales>0.0</sales>  
        <rec>0.0</rec>  
        <val>0.0</val>  
        <id-1/>  
        <id-2/>  
        <id-3/>  
        <unit-pr>13.0</unit-pr>  
        <eff-dt>2015-06-16</eff-dt>  
        <eff-tm>09:12:21</eff-tm>  
    </rp_sendRow>  
</rp_send>