Oracle嵌套xml解析

Posted

技术标签:

【中文标题】Oracle嵌套xml解析【英文标题】:Oracle nested xml parsing 【发布时间】:2020-10-01 07:40:34 【问题描述】:

我有一个 excel,在使用应用程序导入 excel 时,我将其转换为 XML 字符串,然后将其发送到 Oracle 中的程序。下面的代码是我的程序。

PROCEDURE SP_UPLOAD_KALEMS(P_REFCURSOR OUT SYS_REFCURSOR,P_YEAR IN NUMBER,P_MONTH IN NUMBER,P_KALEMS IN CLOB) IS personelId NUMBER; BEGIN
     SAVEPOINT start_tran;
     DELETE FROM HRANALY.WAGE_ACTUAL WA WHERE WA.A_MONTH=P_MONTH AND WA.A_YEAR=P_YEAR;
       FOR r IN (
            select * FROM XMLTABLE('/ArrayOfBaseUpload/BaseUpload'PASSING xmltype(P_KALEMS) 
            COLUMNS  
                SICIL  NUMBER    PATH './SICIL',  
                SAP_ORG_KOD NUMBER     PATH './SAP_ORG_KOD' ,
                POSITION VARCHAR2(100)     PATH './POSITION',
                IS_INFO VARCHAR2(10) PATH './IS',
                FABRIC VARCHAR2(10) PATH './FABRIC',
                COST_CENTER NUMBER     PATH './COST_CENTER' ,
                PERSONE_TYPE VARCHAR2(10) PATH './PERSONE_TYPE',
                UCRET_TIP VARCHAR2(10)     PATH './UCRET_TIP' ,
                BELGE_KOD VARCHAR2(200) PATH './BELGE_KOD',
                TUTAR NUMBER     PATH './TUTAR' ,
                SGK_GUN NUMBER     PATH './SGK_GUN' ,
                SSK_MATRAH NUMBER     PATH './SSK_MATRAH' ,
                SS_MATRAH NUMBER     PATH './SS_MATRAH' ,
                YASAL_NET NUMBER     PATH './YASAL_NET' ,
                ODEME_TUTARI NUMBER     PATH './ODEME_TUTARI' 
                )  PERSONELS
        )LOOP
            personelId:=HRANALY.SEQ_WAGE_MAIN.nextval;
            INSERT INTO  HRANALY.WAGE_ACTUAL(ID,SICIL,SAP_ORG_KOD, POSITION,IS_INFO,FABRIC,COST_CENTER,PERSONE_TYPE,A_MONTH,A_YEAR,UCRET_TIP,BELGE_KOD,
                                             TUTAR,SGK_GUN,SSK_MATRAH,SS_MATRAH,YASAL_NET,ODEME_TUTARI)
            VALUES(personelId,r.SICIL,r.SAP_ORG_KOD,r.POSITION,r.IS_INFO,r.FABRIC,r.COST_CENTER,r.PERSONE_TYPE,P_MONTH,P_YEAR,R.UCRET_TIP,r.BELGE_KOD,
                                             r.TUTAR,r.SGK_GUN,r.SSK_MATRAH,r.SS_MATRAH,r.YASAL_NET,r.ODEME_TUTARI);
            FOR p IN (
                select * FROM XMLTABLE('/ArrayOfBaseUpload/BaseUpload/DETAILS/DetayUpload'PASSING xmltype(P_KALEMS)              
                COLUMNS CODE varchar2(100) PATH './CODE', 
                SICIL NUMBER PATH './../../SICIL',
                AMOUNT NUMBER PATH './AMOUNT') kalems            
            )
            LOOP
                IF r.SICIL=p.SICIL THEN
                    INSERT INTO HRANALY.WAGE_ACTUAL_DETAIL(ID,REF_WAGE,AMOUNT,KALEM_KOD,A_MONTH,A_YEAR)
                    VALUES(HRANALY.SEQ_WAGE_DETAIL.nextval,personelId,p.AMOUNT,p.CODE,P_MONTH,P_YEAR);
                END IF;           
            END LOOP;
        END LOOP;  
        COMMIT;
        OPEN P_REFCURSOR FOR
        SELECT 'SUCCESS' AS RESULT FROM DUAL;  
     EXCEPTION
     WHEN OTHERS THEN
       ROLLBACK TO start_tran;
        OPEN P_REFCURSOR FOR
        SELECT 'ERROR' AS RESULT FROM DUAL;
       RAISE;
    END ; 

我的问题是我在 Excel 中有大约 2000 行和大约 40 列(可能或多或少)。其中 15 个是静态列,保存在 HRANALY.WAGE_ACTUAL 表中,其他列是动态的并插入到 HRANALY.WAGE_ACTUAL_DETAIL 中。 SICIL 是唯一的,例如用户的身份代码。对于一个sicil,可以插入多个细节到HRANALY.WAGE_ACTUAL_DETAIL 我的代码需要太多时间来插入所有变量。我想更快地优化这段代码。我怎样才能加快速度。

我的xml喜欢

<ArrayOfBaseUpload>
    <BaseUpload>
        <SICIL>1</SICIL>
        <SAP_ORG_KOD>500</SAP_ORG_KOD>
        <POSITION>Operator</POSITION>
        <IS>TR - Dikim </IS>
        <FABRIC>IZ01</FABRIC>
        <COST_CENTER>100</COST_CENTER>
        <PERSONE_TYPE>T2</PERSONE_TYPE>
        <UCRET_TIP>Brüt</UCRET_TIP>
        <BELGE_KOD>1</BELGE_KOD>
        <TUTAR>10.00</TUTAR>
        <SGK_GUN>30</SGK_GUN>
        <SSK_MATRAH>100</SSK_MATRAH>
        <SS_MATRAH>100</SS_MATRAH>
        <YASAL_NET>100</YASAL_NET>
        <ODEME_TUTARI>100</ODEME_TUTARI>
        <DETAILS>
            <DetayUpload><CODE>TEMEL_UCRET</CODE><AMOUNT>100</AMOUNT></DetayUpload>//here there can ve 40 data like that
        </DETAILS>
    </BaseUpload>
</ArrayOfBaseUpload>

提前致谢

【问题讨论】:

你知道程序的哪一部分是慢的,所以我们知道应该关注什么吗? (找出问题的好方法是使用 PL/SQL 分析。或者您可以简单地注释掉过程的某些部分并重新运行。)例如,如果只有 INSERT 语句很慢,那么提高性能的简单方法是将结果保存在集合中并使用FORALL 一次写入多行。如果读取和写入都很慢,将循环重新写入单个 SQL 语句可能是有意义的。 减速原因可以是嵌套循环。第一个循环包含大约 2000 个数据,第二个循环包含大约 60000 个数据(如果每个数据有 30 个详细信息),那么这需要太多时间,并且这里还有 if 条件来检查是否相同的 uniqe SICIL 。这可能是时间的主要原因@JonHeller 对于性能问题,了解每行代码的运行时间很重要,而不仅仅是猜测。没有这些信息,很容易出现强迫性调整障碍并优化无关紧要的事情。通过分析和诸如“行 X 占运行时间的 Y%”之类的信息,我们可以确定我们只是在解决真正重要的问题。 【参考方案1】:

编写慢速 SQL 的最佳方法是将 insert/update/delete 放入一个循环中,一次更改一行。

如果您想要快速 SQL,请使用一条语句来更改所有行。用两个 insert-select 语句替换循环应该会加快速度:

insert into hranaly.wage_actual(
  id,sicil,sap_org_kod, position,is_info,fabric,cost_center,persone_type,a_month,a_year,ucret_tip,belge_kod,
  tutar,sgk_gun,ssk_matrah,ss_matrah,yasal_net,odeme_tutari
)
select hranaly.seq_wage_main.nextval, sicil,sap_org_kod,
       position,is_info,fabric,cost_center,persone_type,
       p_month,p_year,ucret_tip,belge_kod,tutar,sgk_gun,
       ssk_matrah,ss_matrah,yasal_net,odeme_tutari
from   xmltable('/ArrayOfBaseUpload/BaseUpload' passing xmltype( p_kalems ) 
columns  
  sicil  number    path './SICIL',  
  sap_org_kod number     path './SAP_ORG_KOD' ,
  position varchar2(100)     path './POSITION',
  is_info varchar2(10) path './IS',
  fabric varchar2(10) path './FABRIC',
  cost_center number     path './COST_CENTER' ,
  persone_type varchar2(10) path './PERSONE_TYPE',
  ucret_tip varchar2(10)     path './UCRET_TIP' ,
  belge_kod varchar2(200) path './BELGE_KOD',
  tutar number     path './TUTAR' ,
  sgk_gun number     path './SGK_GUN' ,
  ssk_matrah number     path './SSK_MATRAH' ,
  ss_matrah number     path './SS_MATRAH' ,
  yasal_net number     path './YASAL_NET' ,
  odeme_tutari number     path './ODEME_TUTARI' 
);

insert into hranaly.wage_actual_detail(id,ref_wage,amount,kalem_kod,a_month,a_year)
  select hranaly.seq_wage_detail.nextval,wa.id,
         p.amount,p.code,p_month,p_year
  from   hranaly.wage_actual wa 
  join   xmltable('/ArrayOfBaseUpload/BaseUpload/DETAILS/DetayUpload' passing xmltype ( p_kalems )              
      columns 
        code varchar2(100) path './CODE', 
        sicil number path './../../SICIL',
        amount number path './AMOUNT'
    ) kalems
  on     wa.a_month= p_month 
  and    wa.a_year=p_year 
  and    wa.sicil=kalems.sicil;

您甚至可以将其变成一个多表插入 (insert all),这可能会更快。不过,如果上述更改仍然太慢,我只会考虑这一点。

【讨论】:

以上是关于Oracle嵌套xml解析的主要内容,如果未能解决你的问题,请参考以下文章

oracle plsql:如何解析 XML 并插入到表中

在 Dart / Flutter 中解析嵌套的 XML

怎么用xml读取数据库信息

oracle PL/SQL解析xml

在 Databricks 中解析嵌套的 XML

使用 powershell 将嵌套的复杂 XML 解析为 CSV