This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: How to improve the performance where a key element used in multiple document()'s


Hi Sun-fu,

> I get solutions all right but the performance is terrible,
> especially when comparing it with behaviour of the following
> approach;

Perhaps I'm missing something, but I think in general that you're
using intermediate RTFs more than you need to, and that might be
slowing things down. For example, you do:

  <xsl:variable name="TransNo">
    <xsl:for-each select="$TransNoheading">
      <xsl:sort select="@OrderNo"/>
      <scode><xsl:value-of select="@OrderNo"/></scode>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="allTransNo"
                select="msxsl:node-set($TransNo)/scode"/>'

  <xsl:for-each select="$allTransNo">
    ...
  </xsl:for-each>

What you're doing here is creating a set of nodes with the values of
the OrderNo attributes of the nodes held in the $TransNoheading
variable, in OrderNo order, and iterating over them.  Instead, you
could just iterate over the $TransNoheading's OrderNo attributes in
order:

  <xsl:for-each select="$TransNoheading/@OrderNo">
     <xsl:sort select="." />
     ...
  </xsl:for-each>

There's no need to build an intermediate RTF, at least given what
you're doing with it currently. Similarly, take a closer look at what
goes on inside the loop:

  <xsl:for-each select="$allTransNo">
    <xsl:variable name="thisNo" select="node()"/>

    <!--   to get the data set and meantime upate key element -->
    <xsl:variable name="sourceLine2">
      <xsl:copy-of
        select="$TransDtl[string(@OrderNo[string($thisNo)])=$thisNo]"/>
    </xsl:variable>
    <xsl:variable name="originalDoc"
                  select="msxsl:node-set($sourceLine2)"/>
    <xsl:variable name="MSource" select="$originalDoc/z:row"/>

    <!-- pick the corresponding data from transDtl of each transno  -->
    <xsl:for-each select="$originalDoc">
      <xsl:apply-templates select="key('TransNo',$thisNo)"
                           mode="transDtl"/>
    </xsl:for-each>
  </xsl:for-each>

The value of the current node in this loop is an OrderNo. You create a
$sourceLine2 variable which holds a copy of the $TransDtl elements
whose OrderNo attribute is equal to this OrderNo, or all of them if
the OrderNo is empty. You then select from this copy those z:row
elements whose @OrderNo element is equal to this OrderNo (these are
the only ones you copied in the first place). As far as I can tell,
this is equivalent to:

  <xsl:for-each select="$TransNoheading/@OrderNo">
     <xsl:sort select="." />
     <xsl:variable name="thisNo" select="." />
     <xsl:for-each select="$originalDoc2">
        <xsl:apply-templates select="key('TransNo', $thisNo)"
                             mode="transDtl" />
     </xsl:for-each>
  </xsl:for-each>

You might be able to get rid of intermediate RTFs in other places as
well without changing the logic. Generally, you should avoid creating
intermediate RTFs unless the alternative is fairly complicated - they
take time to create, take up memory, and make your code less portable
because you have to use extension functions to convert them to node
sets.

In general, it's also worth remembering that each time you use a key
on a new RTF, the processor has to create a new hashtable for that
RTF, just as it does for each new document. If you only use a key's
hashtable once, then it's not worth building it - you can do exactly
the same thing with a single XPath with a predicate, and it doesn't
take up the memory that a hashtable does. For example, rather than:

    <xsl:variable name="MSource" select="$originalDoc/z:row"/>

    <!-- pick the corresponding data from transDtl of each transno  -->
    <xsl:for-each select="$originalDoc">
      <xsl:apply-templates select="key('TransNo',$thisNo)"
                           mode="transDtl"/>
    </xsl:for-each>

You may as well do:

  <xsl:variable name="MSource" select="$originalDoc/z:row"/>
  <xsl:apply-templates select="$MSource[@OrderNo = $thisNo]"
                       mode="transDtl" />

It's only more efficient to use a key with a document or RTF if you
use it more than once with that document or RTF.  (Although there are
other reasons to use a key - they can be simpler than predicates.)
    
I hope that makes sense.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]