https://saxonica.plan.io/https://saxonica.plan.io/favicon.ico2018-10-03T16:08:41ZSaxonica Developer CommunitySaxon - Bug #3945: Poor optimization of `$doc1/descendant-or-self::node()/child::node()`https://saxonica.plan.io/issues/3945?journal_id=123382018-10-03T16:08:41ZMichael Kaymike@saxonica.com
<ul></ul><p>Compiling the query</p>
<pre><code>declare variable $doc external; $doc/descendant-or-self::node()/child::node()
</code></pre>
<p>with the -explain option, both 9.8 and 9.9 fail to deliver this optimization.</p> Saxon - Bug #3945: Poor optimization of `$doc1/descendant-or-self::node()/child::node()`https://saxonica.plan.io/issues/3945?journal_id=123412018-10-03T17:20:06ZMichael Kaymike@saxonica.com
<ul></ul><p>Looking at how the original stylesheet is optimized in 9.8.</p>
<p>SlashExpression <code>docOrder(($doc1) treat as node()/descendant-or-self::node())/child::node()</code></p>
<p>The LHS turns into <code>ConditionalSorter(exists(tail(($doc1) treat as node())), docOrder(($doc1) treat as node()/descendant-or-self::node()))</code></p>
<p>DocumentSorter line 108 turns the SlashExpression (of which the above is the LHS) into <code>ConditionalSorter(exists(tail(($doc1) treat as node())), docOrder((($doc1) treat as node()/descendant-or-self::node())/child::node()))</code></p>
<p>that is, it has moved the final /child::node step inside the ConditionalSorter, which paves the way for the descendant-or-self and child steps to be combined (which happens in SlashExpression.simplifyDescendantPath(), line 287)</p>
<p>The 9.9 optimization path also succeeds in folding the final child::node() step inside the ConditionalSorter, but it seems that the final simplifyDescendantPath() never happens.</p>
<p>Comparing the 9.8 and 9.9 optimization paths step-by-step, 9.8 having optimized the whole template body, goes into global variable extraction (which succeeds) and then does another optimization pass on the result. 9.9 has optimizer options set which inhibit global variable extraction, and the second optimization pass therefore doesn't happen. It's the second pass that recognizes the opportunity to simplify the descendant axis.</p> Saxon - Bug #3945: Poor optimization of `$doc1/descendant-or-self::node()/child::node()`https://saxonica.plan.io/issues/3945?journal_id=123422018-10-03T17:30:31ZMichael Kaymike@saxonica.com
<ul></ul><p>The Configuration is initializing a defaultXsltCompilerInfo during its init sequence, at a point where the variable optimizerOptions holds the optimizer options for Saxon-HE; the value is subsequently changed to the set of options appropriate to Saxon-EE, but this is too late to affect the default XSLT compiler info object.</p>
<p>This causes 9.9 to generate essentially the same code as 9.8 for this example stylesheet.</p>
<p>However, this leaves open the question why two optimization passes should be needed to optimize this particular construct, and why it doesn't get optimized in the simple case of the direct query given in comment #1.</p> Saxon - Bug #3945: Poor optimization of `$doc1/descendant-or-self::node()/child::node()`https://saxonica.plan.io/issues/3945?journal_id=123432018-10-03T17:43:08ZMichael Kaymike@saxonica.com
<ul></ul><p>The issue here seems to be that SlashExpression.simplifyDescendantPath is called during the type-checking phase, and is not called again during the optimization phase. So if optimization generates an expression that is amenable to this rewrite, it won't normally happen, unless we go back to repeat the type-checking, which is normally not encouraged.</p>
<p>Putting another call on simplifyDescendantPath() into the optimize phase solves the problem.</p>
<p>I won't do this for 9.8, however, in the interests of stability.</p> Saxon - Bug #3945: Poor optimization of `$doc1/descendant-or-self::node()/child::node()`https://saxonica.plan.io/issues/3945?journal_id=123442018-10-03T17:45:30ZMichael Kaymike@saxonica.com
<ul><li><strong>Status</strong> changed from <i>New</i> to <i>Resolved</i></li><li><strong>Fix Committed on Branch</strong> <i>9.9</i> added</li></ul><p>Resolved with three patches to 9.9:</p>
<p>(a) ensure that the defaultXsltCompilerInfo in an EnterpriseConfiguration uses all Saxon-EE optimization options</p>
<p>(b) put a call on simplifyDescendantPath() into SlashExpression.optimize()</p>
<p>(c) after rewriting sort(X)/Y as sort(X/Y) in DocumentSorter.optimize(), run an optimization pass over the new slash expression X/Y.</p> Saxon - Bug #3945: Poor optimization of `$doc1/descendant-or-self::node()/child::node()`https://saxonica.plan.io/issues/3945?journal_id=126462018-11-07T18:18:07ZO'Neil Delprattoneil@saxonica.com
<ul><li><strong>Status</strong> changed from <i>Resolved</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li><li><strong>Fixed in Maintenance Release</strong> <i>9.9.0.2</i> added</li></ul><p>Bug fix applied to the Saxon 9.9.0.2 maintenance release.</p>