Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question.

Asked: January 08, 2009 - 9:20 am UTC

Last updated: November 21, 2011 - 11:01 am UTC

Version: 10.2.1

Viewed 10K+ times! This question is

You Asked

Hello Tom,
We have an XML in a remote table which is stored as a CLOB column Type , this is stored in a local table local_table.
The XML is Stored in the following format:
<Transaction> 1
<Legs> n
<payments> n
i.e for each transaction there may be 0 or more leg , for each leg there may be 0 or more than one payment .
For resolving this we created 3 temporary tables locally and tried to extract and upload the transaction, transaction_legs and transaction_payments into respective tables . The below is

for i in ( select xmltype(clob_data) as clob_data,
from local_table
)
loop
for r1 in (
select x.column_value,
extractvalue(x.column_value,'/Transaction/TradeVersion') tradeversion,
extractvalue(x.column_value,'/Transaction/TransactionID') transactionid
from table(xmlsequence(extract(i. clob_data,'/Transaction'))) x
) loop
-- dbms_output.put_line('transaction id '||r1.transactionid);
g_transaction_id := r1.transactionid;
insert into tran values(
,r1.TRADEVERSION
,r1.TRANSACTIONID
for r2 in (
select y.column_value,
extractvalue(y.column_value,'/Leg/Basis') leg_basis,
extractValue(y.column_value,'/Leg/FixedRate') leg_fixedrate
from table(XMLSequence(extract(r1.column_value,'//Leg'))) y
) loop
-- dbms_output.put_line(r2.leg_basis||'Leg number '||r2.leg_legnumber||' currency '||r2.leg_currency);
g_leg_number := r2.leg_legnumber;
insert into tran_leg values( g_transaction_id
,r2.LEG_BASIS
,r2.LEG_FIXEDRATE
);
for r3 in (
select z.column_value,
extractvalue(z.column_value,'/Leg/LegNumber') leg_legnumber ,
extractValue(z.column_value,'/Payment/StartDate') pay_startdate,
extractValue(z.column_value,'/Payment/Value') pay_value
from table(XMLSequence(extract(r2.column_value,'//Payment'))) z
) loop
-- dbms_output.put_line('pay currency '|| r3.pay_currency);
v_line := v_line + 1;
insert into tran_pay values(
,r3.PAY_STARTDATE
,r3.PAY_VALUE
);
if v_line = 500 then
commit;
v_line := 0;
end if;
end loop;
end loop;
end loop;
end loop;

but the above is taking approx. 45-50 minutes to load the data into all the 3 tables. We are trying to reduce the loading time below 10 minutes. Please suggest some alternative solution.
Regards
Senthil

and Tom said...

I asked Laurent Schneider
http://laurentschneider.com/
to look at this (as he enjoys XML and is much more familiar with the syntax than I am :) )

Our idea is "do not go row by row, try bulk". Our suggestion would be less code, bulk SQL. For example:

drop table local_table;
 
create table local_table (clob_data clob);

insert into local_table (clob_data) values
('<TransactionList>
  <Transaction id="1">
    <TradeVersion>1</TradeVersion>
    <TransactionId>1</TransactionId>
    <Leg id="1">
      <LegNumber>1</LegNumber>
      <Basis>1</Basis>
      <FixedRate>1</FixedRate>
      <Payment id="1">
        <StartDate>2000-01-01</StartDate>
        <Value>1</Value>
      </Payment>
      <Payment id="2">
        <StartDate>2000-01-02</StartDate>
        <Value>2</Value>
      </Payment>
    </Leg>
    <Leg id="2">
      <LegNumber>2</LegNumber>
      <Basis>2</Basis>
      <FixedRate>2</FixedRate>
      <Payment id="1">
        <StartDate>2000-02-01</StartDate>
        <Value>10</Value>
      </Payment>
      <Payment id="2">
        <StartDate>2000-02-02</StartDate>
        <Value>20</Value>
      </Payment>
    </Leg>
  </Transaction>
  <Transaction id="2">
    <TradeVersion>2</TradeVersion>
    <TransactionId>2</TransactionId>
    <Leg id="1">
      <LegNumber>21</LegNumber>
      <Basis>21</Basis>
      <FixedRate>21</FixedRate>
      <Payment id="1">
        <StartDate>2002-01-01</StartDate>
        <Value>21</Value>
      </Payment>
      <Payment id="2">
        <StartDate>2002-01-02</StartDate>
        <Value>22</Value>
      </Payment>
    </Leg>
    <Leg id="22">
      <LegNumber>22</LegNumber>
      <Basis>22</Basis>
      <FixedRate>22</FixedRate>
      <Payment id="21">
        <StartDate>2002-02-01</StartDate>
        <Value>210</Value>
      </Payment>
      <Payment id="22">
        <StartDate>2002-02-02</StartDate>
        <Value>220</Value>
      </Payment>
    </Leg>
  </Transaction>
</TransactionList>
');

insert into local_table (clob_data) values
('<TransactionList>
  <Transaction id="31">
    <TradeVersion>31</TradeVersion>
    <TransactionId>31</TransactionId>
    <Leg id="31">
      <LegNumber>31</LegNumber>
      <Basis>31</Basis>
      <FixedRate>31</FixedRate>
      <Payment id="31">
        <StartDate>3000-01-01</StartDate>
        <Value>31</Value>
      </Payment>
    </Leg>
  </Transaction>
</TransactionList>');

commit;

-- insert into tran 
select 
  extractvalue(x.column_value,'/Transaction/TradeVersion/text()') tradeversion,
  extractvalue(x.column_value,'/Transaction/TransactionId/text()') transactionid
from 
  local_table,
  table(xmlsequence(extract(xmltype(clob_data),'/TransactionList/Transaction'))) x;

-- insert into tran_leg 
select 
  extractvalue(x.column_value,'/Transaction/TransactionId/text()') transactionid,
  extractvalue(y.column_value,'/Leg/Basis/text()') leg_basis,
  extractValue(y.column_value,'/Leg/FixedRate/text()') leg_fixedrate
from 
  local_table,
  table(xmlsequence(extract(xmltype(clob_data),'/TransactionList/Transaction'))) x,
  table(xmlsequence(extract(x.column_value,'/Transaction/Leg'))) y;
  
-- insert into tran_pay 
select 
  extractvalue(x.column_value,'/Transaction/TransactionId/text()') transactionid,
  extractvalue(y.column_value,'/Leg/LegNumber/text()') leg_legnumber,
  extractvalue(z.column_value,'/Payment/StartDate/text()') pay_startdate,
  extractValue(z.column_value,'/Payment/Value/text()') pay_value
from 
  local_table,
  table(xmlsequence(extract(xmltype(clob_data),'/TransactionList/Transaction'))) x,
  table(xmlsequence(extract(x.column_value,'/Transaction/Leg'))) y,
  table(xmlsequence(extract(y.column_value,'/Leg/Payment'))) z;


Rating

  (17 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A reader, January 09, 2009 - 7:14 am UTC

Hello Tom,

Thanks for your response , but when i try to insert the below query , it takes a very long time , can you suggest me some way where i can reduce the time to less than 10 min. currently it takes almost an hour to
load approx. 600000 records.

select
extractvalue(x.column_value,'/Transaction/TransactionId/text()')
transactionid,
extractvalue(y.column_value,'/Leg/LegNumber/text()') leg_legnumber,
extractvalue(z.column_value,'/Payment/StartDate/text()') pay_startdate,
extractValue(z.column_value,'/Payment/Value/text()') pay_value
from
local_table,

table(xmlsequence(extract(xmltype(clob_data),'/TransactionList/Transaction')))
x,
table(xmlsequence(extract(x.column_value,'/Transaction/Leg'))) y,
table(xmlsequence(extract(y.column_value,'/Leg/Payment'))) z;

Tom Kyte
January 09, 2009 - 9:48 am UTC

not really, XML is not a 'fast' thing, there is a ton of parsing involved. Sorry, I never saw the point in huge XML files - they are many times larger than they should be and the amount of work involved in parsing them is incredible.

You can try the XML discussion forums on otn.oracle.com

xmltype

Laurent Schneider, January 09, 2009 - 9:00 am UTC

Instead of having the table column of type CLOB, you may want to use the XMLTYPE datatype. You may also want to explore the capabilities of the XQuery language !

drop table local_table;

create table local_table of xmltype;

insert into local_table values
(xmltype('<Transaction id="1">
<TradeVersion>1</TradeVersion>
<TransactionId>1</TransactionId>
<Leg id="1">
<LegNumber>1</LegNumber>
<Basis>1</Basis>
<FixedRate>1</FixedRate>
<Payment id="1">
<StartDate>2000-01-01</StartDate>
<Value>1</Value>
</Payment>
<Payment id="2">
<StartDate>2000-01-02</StartDate>
<Value>2</Value>
</Payment>
</Leg>
<Leg id="2">
<LegNumber>2</LegNumber>
<Basis>2</Basis>
<FixedRate>2</FixedRate>
<Payment id="1">
<StartDate>2000-02-01</StartDate>
<Value>10</Value>
</Payment>
<Payment id="2">
<StartDate>2000-02-02</StartDate>
<Value>20</Value>
</Payment>
</Leg>
</Transaction>'));

insert into local_table values
(xmltype('<Transaction id="31">
<TradeVersion>31</TradeVersion>
<TransactionId>31</TransactionId>
<Leg id="31">
<LegNumber>31</LegNumber>
<Basis>31</Basis>
<FixedRate>31</FixedRate>
<Payment id="31">
<StartDate>3000-01-01</StartDate>
<Value>31</Value>
</Payment>
</Leg>
</Transaction>'));

commit;


select
*
from
xmltable('
for $i in ora:view("LOCAL_TABLE")
for $j in $i/Transaction/Leg
for $k in $j/Payment
return
<t>{$i/Transaction/TransactionId}{$j/LegNumber}{$k/StartDate}{$k/Value}</t>
' columns
transactionid number path '/t/TransactionId/text()',
leg_legnumber number path '/t/LegNumber/text()',
pay_startdate date path '/t/StartDate/text()',
value number path '/t/Value/text()'
)
;

TRANSACTIONID LEG_LEGNUMBER PAY_STARTDA VALUE
------------- ------------- ----------- ----------
1 1 01-JAN-2000 1
1 1 02-JAN-2000 2
1 2 01-FEB-2000 10
1 2 02-FEB-2000 20
31 31 01-JAN-3000 31

A reader, January 09, 2009 - 9:14 am UTC

hello Laurent

I tried the below approach also , in both approaches the select statement doespopulate the rows immediately but once i put an insert statment for inserting it takes a long time to insert.


Tom Kyte
January 09, 2009 - 9:53 am UTC

how long does the select take to execute from start to finish (eg: if you are using toad, stop it, toad is horrible for testing this stuff - get into sqlplus and run the query from end to end)

Cool Warnings...

Marco Gralike, January 10, 2009 - 10:08 pm UTC

There are cool "Fair Warnings" on this site and because I have never answered a question here (I didn't know it was so easy to do nowadays...) it was fun to read them (should have known though being a frequent flyer on the personal Tom Kyte blog aka not here).

Anyway,

It depends. It depends a little on your database version and on your XML layout. So I have to do some assumptions.

After reading your issues the first thing that came up was switch your storage. Instead of going for CLOB or XMLType based on CLOB storage (the default if you use XMLType), go for Object Relational XMLType storage or Binary XMLType.

This will behave much more in the "classical" sense and is more flexible. XMLType CLOB based storage is only usefull for document driven handling of XML data. If you are on 11g you can solve a lot of your issues via applying an XMLIndex to it.

An XMLIndex will of course come with a tradeoff but it could immensily improve your select statements in the current XMLType Column situation (so not the CLOB as is example) based on CLOB storage.

So as always, it depends.


XML problem

Marco Gralike, January 10, 2009 - 10:45 pm UTC

By the way my former answer is based on the first question not on Laurent's / Tom's answers.

You will have to treat XML (for instance seen with a relational mindset) that if you deal with XML, that you are trying to insert, for instance, 1 row into 100ths of tables, where some of those tables will be inserted with much more than 1 row.

So most of the time, the storage type is important but also we have to know what you are trying to do and the layout of the XML because this will give a hint on where the "indexes" should go (and not if there is a lot of data manipulation).

What also counts, is the database version. The Oracle XMLDB Development team puts a lot of effort in solving and adding better solutions to deal with XML. Sometimes the progress is huge inbetween versions. One of the reasons that we, Mark Drake, the Sr. Product Manager for Oracle XMLDB, and I always want to know the database version on the OTN Oracle XMLDB Forum.

Sincerly

Marco

Try dbms_lob functions

Georg, January 11, 2009 - 5:19 pm UTC

If the structure of the XML is not too complex, you can try to skip the xml parser altogether and extract the information from the clob yourself using the dbms_lob functions (substr, instr, ...).
We did that some time ago on 9iR2 and got a 12x speedup.



fast select and slow insert?

Laurent Schneider, January 12, 2009 - 6:07 am UTC

If the SELECT I provided is very fast and the INSERT is very slow, I may wonder if this is really related to xml...

XML Problem

Marco Gralike, January 12, 2009 - 7:41 am UTC

I still very well could be Laurent. It depends a little on how much data is been tested with by the questioner.

There is a difference between CLOB, XMLType COLUMN based on CLOB and XMLType TABLE based on CLOB as you used it in your example.

The XMLType TABLE, based on CLOB storage, has 1 extra unique index on the "hidden" column SYS_NC_OID$. Because we don't have all the info, this actually could make a difference and explain why a select is fast and an insert is slower (although I would indeed expect it not to be "That" much slower).

Have a look at the following...

SQL> conn asktom/asktom
Connected.

SQL> set long 1000000
SQL> set pages 5000

SQL> col SEGMENT_NAME for a50
SQL> col SEGMENT_TYPE for a15
SQL> col BYTES for 99999999999

SQL> exec dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'STORAGE', FALSE);


PL/SQL procedure successfully completed.


SQL> ---- CLOB ---

SQL> select segment_name, segment_type, bytes from user_segments;

no rows selected

SQL> create table local_table (clob_data clob);

Table created.

SQL> select segment_name, segment_type, bytes from user_segments;

SEGMENT_NAME                                       SEGMENT_TYPE           BYTES
-------------------------------------------------- --------------- ------------
LOCAL_TABLE                                        TABLE                  65536
SYS_LOB0000074510C00001$$                          LOBSEGMENT             65536
SYS_IL0000074510C00001$$                           LOBINDEX               65536

SQL> select dbms_metadata.get_ddl('TABLE','LOCAL_TABLE',user) from dual;

DBMS_METADATA.GET_DDL('TABLE','LOCAL_TABLE',USER)
--------------------------------------------------------------------------------

  CREATE TABLE "ASKTOM"."LOCAL_TABLE"
   (    "CLOB_DATA" CLOB
   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  TABLESPACE "USERS"
 LOB ("CLOB_DATA") STORE AS BASICFILE (
 TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION
  NOCACHE LOGGING )



SQL> drop table LOCAL_TABLE purge;

Table dropped.

SQL> select segment_name, segment_type, bytes from user_segments;

no rows selected

SQL> ---- XMLTYPE Column Based on CLOB Storage---

SQL> create table local_table (clob_data XMLTYPE);

Table created.

SQL> select segment_name, segment_type, bytes from user_segments;

SEGMENT_NAME                                       SEGMENT_TYPE           BYTES
-------------------------------------------------- --------------- ------------
LOCAL_TABLE                                        TABLE                  65536
SYS_LOB0000074513C00002$$                          LOBSEGMENT             65536
SYS_IL0000074513C00002$$                           LOBINDEX               65536


SQL> select dbms_metadata.get_ddl('TABLE','LOCAL_TABLE',user) from dual;

DBMS_METADATA.GET_DDL('TABLE','LOCAL_TABLE',USER)
--------------------------------------------------------------------------------

  CREATE TABLE "ASKTOM"."LOCAL_TABLE"
   (    "CLOB_DATA" "XMLTYPE"
   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  TABLESPACE "USERS"
  XMLTYPE COLUMN "CLOB_DATA" STORE AS BASICFILE CLOB (
  TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
  NOCACHE LOGGING )

SQL> drop table LOCAL_TABLE purge;

Table dropped.

SQL> select segment_name, segment_type, bytes from user_segments;

no rows selected

SQL> ---- XMLTYPE TABLE Based on CLOB Storage---

SQL> create table local_table of xmltype;

Table created.

SQL>  select segment_name, segment_type, bytes from user_segments;

SEGMENT_NAME                                       SEGMENT_TYPE           BYTES
-------------------------------------------------- --------------- ------------
LOCAL_TABLE                                        TABLE                  65536
SYS_LOB0000074527C00003$$                          LOBSEGMENT             65536
SYS_IL0000074527C00003$$                           LOBINDEX               65536
SYS_C0010957                                       INDEX                  65536


SQL> select dbms_metadata.get_ddl('TABLE','LOCAL_TABLE',user) from dual;

DBMS_METADATA.GET_DDL('TABLE','LOCAL_TABLE',USER)
--------------------------------------------------------------------------------

  CREATE TABLE "ASKTOM"."LOCAL_TABLE" OF "XMLTYPE"
 OIDINDEX  ( PCTFREE 10 INITRANS 2 MAXTRANS 255 
  TABLESPACE "USERS" )
 PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  TABLESPACE "USERS"
 XMLTYPE COLUMN OBJECT_VALUE STORE AS BASICFILE CLOB (
  TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
  NOCACHE LOGGING )


SQL> select INDEX_NAME, INDEX_TYPE, UNIQUENESS, TABLE_NAME from user_indexes;

INDEX_NAME                     INDEX_TYPE                  UNIQUENES TABLE_NAME
------------------------------ --------------------------- --------- ------------------------------
SYS_C0010957                   NORMAL                      UNIQUE    LOCAL_TABLE
SYS_IL0000074527C00003$$       LOB                         UNIQUE    LOCAL_TABLE

SQL> set lines 80

SQL> select * from user_ind_columns;

INDEX_NAME                     TABLE_NAME
------------------------------ ------------------------------
COLUMN_NAME
--------------------------------------------------------------------------------
COLUMN_POSITION COLUMN_LENGTH CHAR_LENGTH DESC
--------------- ------------- ----------- ----
SYS_C0010957                   LOCAL_TABLE
SYS_NC_OID$
              1            16           0 ASC


SQL> select * from user_constraints
  2  ;

OWNER
--------------------------------------------------------------------------------
CONSTRAINT_NAME                C TABLE_NAME
------------------------------ - ------------------------------
SEARCH_CONDITION
--------------------------------------------------------------------------------
R_OWNER
--------------------------------------------------------------------------------
R_CONSTRAINT_NAME              DELETE_RU STATUS   DEFERRABLE     DEFERRED
------------------------------ --------- -------- -------------- ---------
VALIDATED     GENERATED      BAD RELY LAST_CHANGE
------------- -------------- --- ---- ------------------
INDEX_OWNER                    INDEX_NAME                     INVALID
------------------------------ ------------------------------ -------
VIEW_RELATED
--------------
ASKTOM
SYS_C0010957                   U LOCAL_TABLE


                                         ENABLED  NOT DEFERRABLE IMMEDIATE
VALIDATED     GENERATED NAME          12-JAN-09
ASKTOM                         SYS_C0010957





Laurent Schneider, January 12, 2009 - 9:07 am UTC

the user wrote : "in both approaches the select statement does populate the rows immediately"

Once the data is populated, as number/varchar/date, why in the hell in the insert taking so much time?

Maybe a trigger on the tran_pay table...

Object Relational example

A reader, January 12, 2009 - 9:55 am UTC

SQL> set echo on
SQL> spool testase.log
SQL> --
SQL> connect / as sysdba
Connected.
SQL> --
SQL> set define on
SQL> set timing on
SQL> --
SQL> define USERNAME = XDBTEST
SQL> --
SQL> def PASSWORD = XDBTEST
SQL> --
SQL> def USER_TABLESPACE = USERS
SQL> --
SQL> def TEMP_TABLESPACE = TEMP
SQL> --
SQL> drop user &USERNAME cascade
  2  /
old   1: drop user &USERNAME cascade
new   1: drop user XDBTEST cascade

User dropped.

Elapsed: 00:00:00.71
SQL> grant create any directory, drop any directory, connect, resource, alter session, create view to &USERNAME identified by &PASSW
ORD
  2  /
old   1: grant create any directory, drop any directory, connect, resource, alter session, create view to &USERNAME identified by &P
ASSWORD
new   1: grant create any directory, drop any directory, connect, resource, alter session, create view to XDBTEST identified by XDBT
EST

Grant succeeded.

Elapsed: 00:00:00.01
SQL> alter user &USERNAME default tablespace &USER_TABLESPACE temporary tablespace &TEMP_TABLESPACE
  2  /
old   1: alter user &USERNAME default tablespace &USER_TABLESPACE temporary tablespace &TEMP_TABLESPACE
new   1: alter user XDBTEST default tablespace USERS temporary tablespace TEMP

User altered.

Elapsed: 00:00:00.01
SQL> connect &USERNAME/&PASSWORD
Connected.
SQL> --
SQL> var SCHEMAURL varchar2(256)
SQL> var XMLSCHEMA CLOB
SQL> --
SQL> set define off
SQL> --
SQL> begin
  2    :SCHEMAURL := 'http://xmlns.example.com/askTom/TransactionList.xsd';
  3    :XMLSCHEMA :=
  4  '<?xml version="1.0" encoding="UTF-8"?>
  5  <!--W3C Schema generated by XMLSpy v2008 rel. 2 sp2 (http://www.altova.com)-->
  6  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb" xdb:storeVarrayAsTable="true">
  7     <xs:element name="TransactionList" type="transactionListType" xdb:defaultTable="LOCAL_TABLE"/>
  8     <xs:complexType name="transactionListType"  xdb:maintainDOM="false" xdb:SQLType="TRANSACTION_LIST_T">
  9             <xs:sequence>
 10                     <xs:element name="Transaction" type="transactionType" maxOccurs="unbounded" xdb:SQLCollType="TRANSACTION_V"/
>
 11             </xs:sequence>
 12     </xs:complexType>
 13     <xs:complexType name="transactionType" xdb:maintainDOM="false"  xdb:SQLType="TRANSACTION_T">
 14             <xs:sequence>
 15                     <xs:element name="TradeVersion" type="xs:integer"/>
 16                     <xs:element name="TransactionId" type="xs:integer"/>
 17                     <xs:element name="Leg" type="legType" maxOccurs="unbounded" xdb:SQLCollType="LEG_V"/>
 18             </xs:sequence>
 19             <xs:attribute name="id" type="xs:integer" use="required"/>
 20     </xs:complexType>
 21     <xs:complexType name="paymentType"  xdb:maintainDOM="false" xdb:SQLType="PAYMENT_T">
 22             <xs:sequence>
 23                     <xs:element name="StartDate" type="xs:date"/>
 24                     <xs:element name="Value" type="xs:integer"/>
 25             </xs:sequence>
 26             <xs:attribute name="id" type="xs:integer" use="required"/>
 27     </xs:complexType>
 28     <xs:complexType name="legType"  xdb:maintainDOM="false"  xdb:SQLType="LEG_T">
 29             <xs:sequence>
 30                     <xs:element name="LegNumber" type="xs:integer"/>
 31                     <xs:element name="Basis" type="xs:integer"/>
 32                     <xs:element name="FixedRate" type="xs:integer"/>
 33                     <xs:element name="Payment" type="paymentType" maxOccurs="unbounded"  xdb:SQLCollType="PAYMENT_V"/>
 34             </xs:sequence>
 35             <xs:attribute name="id" type="xs:integer" use="required"/>
 36     </xs:complexType>
 37  </xs:schema>';
 38  end;
 39  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SQL> set define on
SQL> --
SQL> declare
  2    res boolean;
  3    xmlSchema xmlType := xmlType(:XMLSCHEMA);
  4  begin
  5    dbms_xmlschema.registerSchema
  6    (
  7      schemaurl => :schemaURL,
  8      schemadoc => xmlSchema,
  9      local     => TRUE,
 10      genTypes  => TRUE,
 11      genBean   => FALSE,
 12      genTables => TRUE
 13    );
 14  end;
 15  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.54
SQL> desc LOCAL_TABLE
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
TABLE of SYS.XMLTYPE(XMLSchema "http://xmlns.example.com/askTom/TransactionList.xsd" Element "TransactionList") STORAGE Object-relat
ional TYPE "TRANSACTION_LIST_T"

SQL> --
SQL> create or replace VIEW TRAN_VIEW
  2  as
  3  select
  4    extractvalue(x.column_value,'/Transaction/TradeVersion/text()') tradeversion,
  5    extractvalue(x.column_value,'/Transaction/TransactionId/text()') transactionid
  6  from
  7    local_table,
  8    table(xmlsequence(extract(OBJECT_VALUE,'/TransactionList/Transaction'))) x
  9  /

View created.

Elapsed: 00:00:00.01
SQL> create or replace VIEW TRAN_LEG_VIEW
  2  as
  3  select
  4    extractvalue(x.column_value,'/Transaction/TransactionId/text()') transactionid,
  5    extractvalue(y.column_value,'/Leg/Basis/text()') leg_basis,
  6    extractValue(y.column_value,'/Leg/FixedRate/text()') leg_fixedrate
  7  from
  8    local_table,
  9    table(xmlsequence(extract(OBJECT_VALUE,'/TransactionList/Transaction'))) x,
 10    table(xmlsequence(extract(x.column_value,'/Transaction/Leg'))) y
 11  /

View created.

Elapsed: 00:00:00.03
SQL> create or replace VIEW TRAN_LEG_PAY_VIEW
  2  as
  3  select
  4    extractvalue(x.column_value,'/Transaction/TransactionId/text()') transactionid,
  5    extractvalue(y.column_value,'/Leg/LegNumber/text()') leg_legnumber,
  6    extractvalue(z.column_value,'/Payment/StartDate/text()') pay_startdate,
  7    extractValue(z.column_value,'/Payment/Value/text()') pay_value
  8  from
  9    local_table,
 10    table(xmlsequence(extract(OBJECT_VALUE,'/TransactionList/Transaction'))) x,
 11    table(xmlsequence(extract(x.column_value,'/Transaction/Leg'))) y,
 12    table(xmlsequence(extract(y.column_value,'/Leg/Payment'))) z
 13  /

View created.

Elapsed: 00:00:00.04
SQL> desc TRAN_VIEW
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TRADEVERSION                                       NUMBER(38)
 TRANSACTIONID                                      NUMBER(38)

SQL> --
SQL> desc TRAN_LEG_VIEW
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TRANSACTIONID                                      NUMBER(38)
 LEG_BASIS                                          NUMBER(38)
 LEG_FIXEDRATE                                      NUMBER(38)

SQL> --
SQL> desc TRAN_LEG_PAY_VIEW
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TRANSACTIONID                                      NUMBER(38)
 LEG_LEGNUMBER                                      NUMBER(38)
 PAY_STARTDATE                                      DATE
 PAY_VALUE                                          NUMBER(38)

SQL> --
SQL> set long 10000 pages 0 lines 128
SQL> set timing on
SQL> set autotrace on explain
SQL> --
SQL> VAR DOC1 CLOB
SQL> VAR DOC2 CLOB
SQL> --
SQL> begin
  2    :DOC1 :=
  3  '<TransactionList>
  4    <Transaction id="1">
  5      <TradeVersion>1</TradeVersion>
  6      <TransactionId>1</TransactionId>
  7      <Leg id="1">
  8        <LegNumber>1</LegNumber>
  9        <Basis>1</Basis>
 10        <FixedRate>1</FixedRate>
 11        <Payment id="1">
 12          <StartDate>2000-01-01</StartDate>
 13          <Value>1</Value>
 14        </Payment>
 15        <Payment id="2">
 16          <StartDate>2000-01-02</StartDate>
 17          <Value>2</Value>
 18        </Payment>
 19      </Leg>
 20      <Leg id="2">
 21        <LegNumber>2</LegNumber>
 22        <Basis>2</Basis>
 23        <FixedRate>2</FixedRate>
 24        <Payment id="1">
 25          <StartDate>2000-02-01</StartDate>
 26          <Value>10</Value>
 27        </Payment>
 28        <Payment id="2">
 29          <StartDate>2000-02-02</StartDate>
 30          <Value>20</Value>
 31        </Payment>
 32      </Leg>
 33    </Transaction>
 34    <Transaction id="2">
 35      <TradeVersion>2</TradeVersion>
 36      <TransactionId>2</TransactionId>
 37      <Leg id="1">
 38        <LegNumber>21</LegNumber>
 39        <Basis>21</Basis>
 40        <FixedRate>21</FixedRate>
 41        <Payment id="1">
 42          <StartDate>2002-01-01</StartDate>
 43          <Value>21</Value>
 44        </Payment>
 45        <Payment id="2">
 46          <StartDate>2002-01-02</StartDate>
 47          <Value>22</Value>
 48        </Payment>
 49      </Leg>
 50      <Leg id="22">
 51        <LegNumber>22</LegNumber>
 52        <Basis>22</Basis>
 53        <FixedRate>22</FixedRate>
 54        <Payment id="21">
 55          <StartDate>2002-02-01</StartDate>
 56          <Value>210</Value>
 57        </Payment>
 58        <Payment id="22">
 59          <StartDate>2002-02-02</StartDate>
 60          <Value>220</Value>
 61        </Payment>
 62      </Leg>
 63    </Transaction>
 64  </TransactionList>';
 65    :DOC2 :=
 66  '<TransactionList>
 67    <Transaction id="31">
 68      <TradeVersion>31</TradeVersion>
 69      <TransactionId>31</TransactionId>
 70      <Leg id="31">
 71        <LegNumber>31</LegNumber>
 72        <Basis>31</Basis>
 73        <FixedRate>31</FixedRate>
 74        <Payment id="31">
 75          <StartDate>3000-01-01</StartDate>
 76          <Value>31</Value>
 77        </Payment>
 78      </Leg>
 79    </Transaction>
 80  </TransactionList>';
 81  end;
 82  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
SQL> insert into LOCAL_TABLE values ( xmltype(:DOC1))
  2  /

1 row created.

Elapsed: 00:00:00.06

Execution Plan
----------------------------------------------------------
Plan hash value: 1

----------------------------------------------------------------------------------------
| Id  | Operation                | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |             |     1 |   100 |     1   (0)| 00:00:01 |
|   1 |  LOAD TABLE CONVENTIONAL | LOCAL_TABLE |       |       |            |          |
----------------------------------------------------------------------------------------

SQL> insert into LOCAL_TABLE values ( xmltype(:DOC2))
  2  /

1 row created.

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 1

----------------------------------------------------------------------------------------
| Id  | Operation                | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |             |     1 |   100 |     1   (0)| 00:00:01 |
|   1 |  LOAD TABLE CONVENTIONAL | LOCAL_TABLE |       |       |            |          |
----------------------------------------------------------------------------------------

SQL> select * from TRAN_VIEW
  2  /
           1             1
           2             2
          31            31

Elapsed: 00:00:00.03

Execution Plan
----------------------------------------------------------
Plan hash value: 1619272694

---------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                                |     3 |   228 |     6   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |                                |       |       |            |       |
|   2 |   NESTED LOOPS               |                                |     3 |   228 |     6   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL         | SYS_NTay4t3YzFTaa1bgr/nuBcZA== |     3 |   138 |     3   (0)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN         | SYS_C0010076                   |     1 |       |     0   (0)| 00:00:01 |
|*  5 |   TABLE ACCESS BY INDEX ROWID| LOCAL_TABLE                    |     1 |    30 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("SYS_NC_TYPEID$" IS NOT NULL)
   4 - access("NESTED_TABLE_ID"="LOCAL_TABLE"."SYS_NC0000800009$")
   5 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege
              xmlns="http://xmlns.oracle.com/xdb/acl.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd http://xmlns.oracle.com/xdb/acl.xsd
              DAV:http://xmlns.oracle.com/xdb/dav.xsd"><read-properties/><read-contents/></privilege>'))=1)

Note
-----
   - dynamic sampling used for this statement

SQL> select * from TRAN_LEG_VIEW
  2  /
            1          1             1
            1          2             2
            2         21            21
            2         22            22
           31         31            31

Elapsed: 00:00:00.03

Execution Plan
----------------------------------------------------------
Plan hash value: 957660098

----------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                                |     5 |   595 |    10  (10)| 00:00:01 |
|*  1 |  HASH JOIN                    |                                |     5 |   595 |    10  (10)| 00:00:01 |
|   2 |   NESTED LOOPS                |                                |       |       |            |          |
|   3 |    NESTED LOOPS               |                                |     3 |   219 |     6   (0)| 00:00:01 |
|*  4 |     TABLE ACCESS FULL         | SYS_NTay4t3YzFTaa1bgr/nuBcZA== |     3 |   129 |     3   (0)| 00:00:01 |
|*  5 |     INDEX UNIQUE SCAN         | SYS_C0010076                   |     1 |       |     0   (0)| 00:00:01 |
|*  6 |    TABLE ACCESS BY INDEX ROWID| LOCAL_TABLE                    |     1 |    30 |     1   (0)| 00:00:01 |
|*  7 |   TABLE ACCESS FULL           | SYS_NT3F3WjzVIRNSZ17ljquURTw== |     5 |   230 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("NESTED_TABLE_ID"="SYS_ALIAS_0"."SYS_NC0000800009$")
   4 - filter("SYS_NC_TYPEID$" IS NOT NULL)
   5 - access("NESTED_TABLE_ID"="LOCAL_TABLE"."SYS_NC0000800009$")
   6 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege
              xmlns="http://xmlns.oracle.com/xdb/acl.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd http://xmlns.oracle.com/xdb/acl.xsd
              DAV:http://xmlns.oracle.com/xdb/dav.xsd"><read-properties/><read-contents/></privilege>'))=1)
   7 - filter("SYS_NC_TYPEID$" IS NOT NULL)

Note
-----
   - dynamic sampling used for this statement

SQL> select * from TRAN_LEG_PAY_VIEW
  2  /
            1             1 01-JAN-00          1
            1             1 02-JAN-00          2
            1             2 01-FEB-00         10
            1             2 02-FEB-00         20
            2            21 01-JAN-02         21
            2            21 02-JAN-02         22
            2            22 01-FEB-02        210
            2            22 02-FEB-02        220
           31            31 01-JAN-00         31

9 rows selected.

Elapsed: 00:00:00.07

Execution Plan
----------------------------------------------------------
Plan hash value: 1062323250

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                                |     9 |  1422 |    13   (8)| 00:00:01 |
|*  1 |  HASH JOIN                     |                                |     9 |  1422 |    13   (8)| 00:00:01 |
|*  2 |   HASH JOIN                    |                                |     5 |   580 |    10  (10)| 00:00:01 |
|   3 |    NESTED LOOPS                |                                |       |       |            |          |
|   4 |     NESTED LOOPS               |                                |     3 |   219 |     6   (0)| 00:00:01 |
|*  5 |      TABLE ACCESS FULL         | SYS_NTay4t3YzFTaa1bgr/nuBcZA== |     3 |   129 |     3   (0)| 00:00:01 |
|*  6 |      INDEX UNIQUE SCAN         | SYS_C0010076                   |     1 |       |     0   (0)| 00:00:01 |
|*  7 |     TABLE ACCESS BY INDEX ROWID| LOCAL_TABLE                    |     1 |    30 |     1   (0)| 00:00:01 |
|*  8 |    TABLE ACCESS FULL           | SYS_NT3F3WjzVIRNSZ17ljquURTw== |     5 |   215 |     3   (0)| 00:00:01 |
|*  9 |   TABLE ACCESS FULL            | SYS_NTmU6LyM7ERsO+wO07D3tQuQ== |     9 |   378 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("NESTED_TABLE_ID"="SYS_ALIAS_1"."SYS_NC0000900010$")
   2 - access("NESTED_TABLE_ID"="SYS_ALIAS_0"."SYS_NC0000800009$")
   5 - filter("SYS_NC_TYPEID$" IS NOT NULL)
   6 - access("NESTED_TABLE_ID"="LOCAL_TABLE"."SYS_NC0000800009$")
   7 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege
              xmlns="http://xmlns.oracle.com/xdb/acl.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd http://xmlns.oracle.com/xdb/acl.xsd
              DAV:http://xmlns.oracle.com/xdb/dav.xsd"><read-properties/><read-contents/></privilege>'))=1)
   8 - filter("SYS_NC_TYPEID$" IS NOT NULL)
   9 - filter("SYS_NC_TYPEID$" IS NOT NULL)

Note
-----
   - dynamic sampling used for this statement

SQL>


Note this uses an XMLSchema to create an optimized storage structure for you XML. Defining an XML Schema allows the DB to understand the structure of the XML it will be processing, enabling it to optimize operations on the XML.

I don't know which DB version you are working with, so I've used older syntax that should work with 9.2.x and later. However in 10.2.x and 11.1.x I would recommend XMLTable rather than extractValue()/XMLSequence. Also what is the size of the XML files that are being loaded. If there are really large (200MB or greater) you might want to consider loading them directly into local table using FTP.

Hope this helps

Guessing

Marco Gralike, January 12, 2009 - 10:25 am UTC

@Laurent

You could be right, but because we don't have all the details, it will be a guessing game.

Your XMLTable solution does 1 loop / pickler fetch less in memory than the first given statement of the questioner...

An object relational storage XMLType is more flexible and if defined correctly will give the possibility to do a query re-write. Far better options than a collection iterator pickler fetch.

SQL> select
  2    *
  3  from
  4    xmltable('
  5    for $i in ora:view("LOCAL_TABLE")
  6      for $j in $i/Transaction/Leg
  7        for $k in $j/Payment
  8          return
  9  <t>{$i/Transaction/TransactionId}{$j/LegNumber}{$k/StartDate}{$k/Value}</t>
 10  '   columns
 11        transactionid number path '/t/TransactionId/text()',
 12        leg_legnumber number path '/t/LegNumber/text()',
 13        pay_startdate date path '/t/StartDate/text()',
 14        value number path '/t/Value/text()'
 15      )
 16  ;

TRANSACTIONID LEG_LEGNUMBER PAY_STARTDATE           VALUE
------------- ------------- ------------------ ----------
            1             1 01-JAN-00                   1
            1             1 02-JAN-00                   2
            1             2 01-FEB-00                  10
            1             2 02-FEB-00                  20
           31            31 01-JAN-00                  31


Execution Plan
----------------------------------------------------------
Plan hash value: 1004155021

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                        |   133M|   249G|   443K  (1)| 01:28:48 |
|   1 |  NESTED LOOPS                       |                        |   133M|   249G|   443K  (1)| 01:28:48 |
|   2 |   NESTED LOOPS                      |                        | 16336 |    31M|    59   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL                | LOCAL_TABLE            |     2 |  4004 |     3   (0)| 00:00:01 |
|   4 |    COLLECTION ITERATOR PICKLER FETCH| XMLSEQUENCEFROMXMLTYPE |       |       |            |          |
|   5 |   COLLECTION ITERATOR PICKLER FETCH | XMLSEQUENCEFROMXMLTYPE |       |       |            |          |
--------------------------------------------------------------------------------------------------------------


Note
-----
   - dynamic sampling used for this statement


SQL> select
  2    extractvalue(value(x),'/Transaction/TransactionId/text()')
  3    transactionid,
  4    extractvalue(value(y),'/Leg/LegNumber/text()') leg_legnumber,
  5    extractvalue(value(z),'/Payment/StartDate/text()') pay_startdate,
  6    extractValue(value(z),'/Payment/Value/text()') pay_value
  7  from
  8    local_table t,
  9    table(xmlsequence(extract(value(t),'/TransactionList/Transaction'))) x,
 10    table(xmlsequence(extract(value(x),'/Transaction/Leg'))) y,
 11    table(xmlsequence(extract(value(y),'/Leg/Payment'))) z
 12  ;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 2150604070

---------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                        |  1089G|  1990T|  3626M  (1)|999:59:59 |
|   1 |  NESTED LOOPS                        |                        |  1089G|  1990T|  3626M  (1)|999:59:59 |
|   2 |   NESTED LOOPS                       |                        |   133M|   249G|   443K  (1)| 01:28:48 |
|   3 |    NESTED LOOPS                      |                        | 16336 |    31M|    59   (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL                | LOCAL_TABLE            |     2 |  4004 |     3   (0)| 00:00:01 |
|   5 |     COLLECTION ITERATOR PICKLER FETCH| XMLSEQUENCEFROMXMLTYPE |       |       |            |          |
|   6 |    COLLECTION ITERATOR PICKLER FETCH | XMLSEQUENCEFROMXMLTYPE |       |       |            |          |
|   7 |   COLLECTION ITERATOR PICKLER FETCH  | XMLSEQUENCEFROMXMLTYPE |       |       |            |          |
---------------------------------------------------------------------------------------------------------------


Note
-----
   - dynamic sampling used for this statement

Laurent Schneider, January 12, 2009 - 10:31 am UTC

is there more than one transaction per database row?

A reader, January 14, 2009 - 1:01 am UTC

Laurent :

I don't have any triggers defined on those tables , they are just used for loading data from xml extract.

Laurent Schneider, January 14, 2009 - 11:22 am UTC

it was just a wild guess. If the select is fast (is it fast? did you run it in sqlplus?), then the insert should not be that slow. You probably need to apply a traditional tuning approach (for instance comparing your approach with the insert into tran_leg as select ... using runstats, http://asktom.oracle.com/tkyte/runstats.html )

If the select is fast, I really cannot see yet how the insert could be related to xml...

XML Type to CLOB

Marin Velichkov, March 14, 2009 - 5:11 am UTC

Hi Tom,
I have to transfer xml_type from destination DB to CLOB in source DB  I have that problem:

SQL> conn system@oradb;
Connected.
SQL> desc dec2008.dec_zddfl50_2008;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 DEC_ID                                    NOT NULL NUMBER
 TP_ID                                     NOT NULL NUMBER
 DATA                                               SYS.XMLTYPE(XMLSchema "http:
                                                    //inetdec.nra.bg/pls/dec/xsd
                                                    /dec50_2008.xsd" Element "de
                                                    c502008") STORAGE Object-rel
                                                    ational TYPE "dec502008802_T
                                                    "
 INNO                                               VARCHAR2(30)
 INNODATE                                           DATE
 RECEIVEDATE                                        DATE
 LASTMODIFIED                                       DATE
 STATUS                                    NOT NULL NUMBER(38)
 ENTRY                                     NOT NULL NUMBER(38)
 DOC_ID                                             NUMBER(38)
 CERT_ID                                            NUMBER(38)

SQL> conn iris_sa@nrahq
Connected.
SQL> create table test_xml_data
  2  (dec_id number not null,
  3  xml_data clob);

Table created.
SQL> insert into test_xml_data
  2  (dec_id, xml_data)
  3  select dec_id, fromis.data.getclobval() xml_data
  4  from dec2008.dec_zddfl50_2008@ORADB.REGRESS.RDBMS.DEV.US.ORACLE.COM fromis
  5  where fromis.status=1 and
  6         trunc(fromis.lastmodified)=trunc(sysdate-2)
  7  /

92 rows created.

SQL> commit
  2  /

Commit complete.

SQL> create or replace procedure test_xmldata is
  2  begin
  3    insert into test_xml_data
  4    (dec_id, xml_data)
  5    select dec_id, fromis.data.getclobval() xml_data
  6    from dec2008.dec_zddfl50_2008@ORADB.REGRESS.RDBMS.DEV.US.ORACLE.COM fromis
  7    where fromis.status=1 and
  8           trunc(fromis.lastmodified)=trunc(sysdate-1);
  9  end;
 10  /

Warning: Procedure created with compilation errors.

SQL> show errors
Errors for PROCEDURE TEST_XMLDATA:

LINE/COL ERROR                                                                  
-------- -----------------------------------------------------------------      
3/3      PL/SQL: SQL Statement ignored                                          
5/18     PL/SQL: ORA-21700: object does not exist or is marked for delete       
SQL> 


How can I solve this problem?

Thanks

Marin Velichkov 

Tom Kyte
March 16, 2009 - 9:23 am UTC

Need help to reproduce, construct a standalone test case from START to FINISH (eg: I had to build a create table statement, I shouldn't have to do that, you should have done that - it might be important - the manner in which you typed in the create table, I had to make it up, make sure it is a create table statement ANYONE IN THE WORLD can execute)

versions would be useful too perhaps.


ops$tkyte%ORA10GR2> create table dec_zddfl50_2008
  2  (
  3  DEC_ID       NUMBER NOT NULL,
  4  TP_ID        NUMBER NOT NULL,
  5  DATA         SYS.XMLTYPE,
  6  INNO         VARCHAR2(30),
  7  INNODATE     DATE,
  8  RECEIVEDATE  DATE,
  9  LASTMODIFIED DATE,
 10  STATUS       NUMBER(38) NOT NULL,
 11  ENTRY        NUMBER(38) NOT NULL,
 12  DOC_ID       NUMBER(38),
 13  CERT_ID      NUMBER(38)
 14  )
 15  /

Table created.

ops$tkyte%ORA10GR2> insert into dec_zddfl50_2008 values (1,1,'<x>hello world</x>','abc',sysdate-2,sysdate-2,sysdate-2,1,1,1,1);

1 row created.

ops$tkyte%ORA10GR2> insert into dec_zddfl50_2008 values (1,1,'<x>goodbye </x>','abc',sysdate-1,sysdate-1,sysdate-1,1,1,1,1);

1 row created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> drop table test_xml_data;

Table dropped.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create table test_xml_data
  2  (dec_id number not null,
  3  xml_data clob);

Table created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> insert into test_xml_data
  2  (dec_id, xml_data)
  3  select dec_id, fromis.data.getclobval() xml_data
  4  from dec_zddfl50_2008@ora10gr2@loopback fromis
  5  where fromis.status=1 and
  6         trunc(fromis.lastmodified)=trunc(sysdate-2)
  7  /

1 row created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> commit
  2  /

Commit complete.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create or replace procedure test_xmldata is
  2  begin
  3    insert into test_xml_data
  4    (dec_id, xml_data)
  5    select dec_id, fromis.data.getclobval() xml_data
  6    from dec_zddfl50_2008@ora10gr2@loopback fromis
  7    where fromis.status=1 and
  8           trunc(fromis.lastmodified)=trunc(sysdate-1);
  9  end;
 10  /

Procedure created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> exec test_xmldata;

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> select rownum, data from dec_zddfl50_2008;

    ROWNUM
----------
DATA
-------------------------------------------------------------------------------
         1
<x>hello world</x>

         2
<x>goodbye </x>

Parsing XML in order of 50-100

Sachin, April 18, 2011 - 9:25 am UTC

Tom,
I've gone through your variuos xml parsing posts but over here, I've got some usually performance issue.
I need to have stored procedure which would parse xml contents and insert data into tables such as employee,employee_hist,employee_join_hist.
We should be able to parse the XML file and insert 50 records and rollback all in the case of an error. It is like processing in bulk.

XML UTF-8 Problem

Oracle Learner, November 18, 2011 - 4:45 am UTC

Tom,

I have taken your original solution and implemented this in a simple interface process that runs daily in a production situation and implementation and performance has been excellent for what the requirements are.

However, recently there is a varchar2 narrative field that failed to load (value too long for column) due to a double-byte character: the character set of the Oracle instance being loaded is single-byte.

I could wrap a convert round every column like:

convert(extractvalue(..........),'WE8ISO8859P1, 'UTF8')


but this seems like alot of clutter for every column.

I would like to know if there is a better way, keeping the original code as intact as possible and without changing the table that holds the XML (the XML is stored as a CLOB on the database).

Thanks,
Tom Kyte
November 21, 2011 - 11:01 am UTC

well, if you have UTF8 encoded data - it needs to be converted if you are a single byte database.

Or, you could use NVARCHAR instead of VARCHAR.

If you convert the data - you will change the data - you will lose some of the information converting from UTF8 to WE8ISO.

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here