Weird comparison transformation in XQuery
Added by Denis Sukhoroslov over 8 years ago
Saxon 9.7. I have the following XQuery:
declare default element namespace "http://tpox-benchmark.com/security"; declare variable $sect external; declare variable $pemin external; declare variable $pemax external; declare variable $yield external; for $sec in fn:collection()/Security where $sec[SecurityInformation/*/Sector = $sect and PE[. >= $pemin and . < $pemax] and Yield > $yield] return {$sec/Symbol} {$sec/Name} {$sec/SecurityType} {$sec/SecurityInformation//Sector} {$sec/PE} {$sec/Yield} ;
with params: {pemin=25.0, yield=0.1, sect=Technology, pemax=28.0}
after compilation of expression I do explain and get the following expression tree:
if I understand it correctly, the comparison operators for PE elements were reverted and now the query looks like:
where $sec[SecurityInformation/*/Sector = $sect and PE[. <= $pemin and . > $pemax] and Yield > $yield]
Could someone explain why this happens?
Thanks, Denis.
Replies (3)
Please register to reply
RE: Weird comparison transformation in XQuery - Added by Michael Kay over 8 years ago
where $sec[SecurityInformation/*/Sector = $sect and PE[. >= $pemin and . < $pemax] and Yield > $yield]
if I understand it correctly, the comparison operators for PE elements were reverted and now the query looks like:
where $sec[SecurityInformation/*/Sector = $sect and PE[. <= $pemin and . > $pemax] and Yield > $yield]
If you look more carefully you'll see that it has actually been rewritten as
where $sec[SecurityInformation/*/Sector = $sect and PE[$pemin <= . and $pemax > .] and Yield > $yield]
which is precisely equivalent to the original.
When Saxon detects a many-to-one comparison (in this case the cardinality of the variable references is unknown, because you didn't declare the required types, but the cardinality of "." is always one) then it always rearranges them so the "many" operand is on the left, simply because it simplifies the subsequent analysis and execution to always have it the same way: it means there are fewer cases to consider. For example if you look at GeneralComparison.effectiveBooleanValue you will see that there are only three cases to consider rather than four. In this particular case no further optimizations have taken place after the reordering, but the search for further optimizations will be faster because the search space has been reduced.
Of course in this example it's very likely that $pemin and $pemax will be single numbers. The optimizer can do a much better job if you tell it so by declaring the required types, or by using value comparison operators instead of general comparisons.
RE: Weird comparison transformation in XQuery - Added by Denis Sukhoroslov over 8 years ago
I see, thank you for the info. How can I force Saxon to use value comparison operators?
Thanks, Denis.
RE: Weird comparison transformation in XQuery - Added by Michael Kay over 8 years ago
The "value comparison" operators are "eq", "le", "lt" etc, rather than "=", "<=", "<".
But declaring your types is also very important, e.g.
@let $x as element(invoice) := $invoices[@nr = $invoice-nr]@
tells Saxon that $x will contain exactly one invoice. The optimizer can make a lot of use of that information, and you get better debugging as well because you've built an assertion into your query that will improve the diagnostics when you get things wrong.
Please register to reply