You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The space allocation during parsing/contextualization/flattening of
the parse tree for a large number of similar set operations[*] is not
linear in N, where N is the number of operations (e.g. UNION ALL as
shown in the bug report).
The problem lies within merge_descendants.
[*] It could be any set operations, both DISTINCT and ALL, except
for INTERSECT ALL which isn't flattened.
Contextualization is currently based on recursive dives on the parse
tree, and a large number of e.g. UNION ALL have a parse tree looking
like
UNION ALL
/ \
UNION ALL query
: \
: query
:
UNION ALL
/ \
query query
The arrays holding the children (Query_term_set_op::m_children) on
each level will grow (and then be discarded) as we merge descendants
from the bottom up, ending up with
UNION ALL
|
-----------
| | ... |
1 2 N+1
On the way there we create N m_children arrays containing
SELECT UNION ALL-> [query-1 query-2]
SELECT UNION ALL-> [query-1 query-2 query-3]
:
SELECT UNION ALL-> [query-1 query-2 query-3 .. query-N+1]
the current logic appends the children of the lower set operation
to the list of children to the next level up set operation. This means
we get N arrays with an average of N/2 elements, which is not linear.
Solution: avoid this malign pattern by checking if the lower UNION ALL
has more childen than the upper: in that case add any upper's
child(ren) to the front of the lower UNION ALL's child list, then
using copy (std::move) that array the current array for the higher
level UNION ALL. That way we grow only a single array (moved up the
levels), which grows from 2 to N+1 elements after merge_descendants is
done. Note that in the repro case, the number of children in the
upper set operation ("setop" in the code) is always zero, so we have
no need to add any elements to the front of the m_children array. The
new block for that level will be appended later in the loop for
(Query_term *elt : ql.m_elts) {..}
Change-Id: I3658c27de3f9e20237f530ae2832f5aab80c9927
0 commit comments