views:

409

answers:

5

I would like to create some PL/SQL procedures that return XML as CLOB parameters. I want to just do this (which works fine with simple tests):

create or replace procedure p_xml_test_1(
  p_xml out nocopy clob
) is
begin
  p_xml := '<?xml version="1.0" encoding="utf8" ?>' ||
    '<test><something>some value</something></test>';
end p_xml_test_1;

But I have access to some other source code that basically does this:

create or replace procedure p_xml_test_2(
  p_xml out nocopy clob
) is
  lv_xml clob;
begin
  dbms_lob.createtemporary(
    lob_loc => p_xml,
    cache   => true
  );

  lv_xml := '<?xml version="1.0" encoding="utf8" ?>' ||
    '<test><something>some value</something></test>';

  dbms_lob.writeappend(
    lob_loc => p_xml,
    amount  => length(lv_xml),
    buffer  => lv_xml
  );
end p_xml_test_2;

I'm wondering if the first method will cause any problems for me down the road. Is it ok to do it that way? What is the advantage, if any, to the second method? Thanks!

A: 

I think you should measure the performance of both methods by running them many times in a loop. I think performance is the only difference. Your xml block is short but when you concatenate a big xml block it is faster to concatenate with dbms_low.writeappend than using ||.

(At least it was in Oracle 9, I believe the performance difference is smaller in Oracle 10.)

tuinstoel
A: 

I see no reason why you'd want to use the second one.

If lv_xml was a VARCHAR2 rather than a CLOB then I see a very good reason (the max length of a string literal vs the max length of a CLOB).

darreljnz
A: 

Thanks for the answers. Based on what I read at the site listed below, I'm going to assume that it is in fact a good thing to use dbms_lob.writeappend. If I don't, I might as well be using VARCHAR2s (which won't be large enough in some cases).

If you have a CLOB variable called "l_clob", and you do something like "l_clob := l_clob || l_some_string_to_concatenate;", it will convert the l_clob value on the right side of the equation to a VARCHAR2 before doing the concatenation, possibly giving you invalid results or an error.

http://www.maristream.org/srea/Huge%5FStrings%5FUsing%5FLOBs.htm

Tim
Be wary of following the advice of some random stranger on the internet. That applies especially to blog posts which don't contain crucial information about database version, OS platform, etc. For instance, the code posted above works perfectly well in 11gR1 and (I think) would run in 10g as well - perhaps even 9i. Don't swallow other people's assertions: always test stuff for yourself.
APC
A: 

There is another option which you don't mention: using Oracle's built-in XML functionality (presuming you have a database version of 9i or higher). For instance, generating an XML document from a query is a snip with DBMS_XMLGEN.getXML() or DBMS_XMLGEN.getXMLType().

APC
A: 

I ran the following procedures to compare execution time:

Version 1

create or replace procedure p_xml_test_1(
  p_xml out nocopy clob
) is
  lv_i number;
begin
  for lv_i in 1 .. 999999 loop
    p_xml := p_xml || 'a';
  end loop;
end p_xml_test_1;

Version 2

create or replace procedure p_xml_test_2(
  p_xml out nocopy clob
) is
  lv_xml clob;
  lv_i   number;
begin
  dbms_lob.createtemporary(
    lob_loc => p_xml,
    cache   => true
  );

  for lv_i in 1 .. 999999 loop
    lv_xml := 'a';

    dbms_lob.writeappend(
      lob_loc => p_xml,
      amount  => length(lv_xml),
      buffer  => lv_xml
    );
  end loop;
end p_xml_test_2;

The difference is neglible. Both come in at around .2 seconds consistently.

If I change the procedures to loop to 999999 instead of 10000, version 1's performance starts to decline somewhat (about 39 seconds versus 32 seconds for version2).

Tim