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
Bug#25369742 INCORRECT BEHAVIOUR IN SEL_ARG::RB_INSERT DURING
RANGE QUERY OPTIMIZATION
Summary
========
This patch fixes a wrong reference counting during creation
of RB tree resulting in server exit and also causing incorrect
estimates and thereby wrong plan choice for some cases.
Details
======
Range optimizer creates a RB tree representing the entire
where condition present in the query. Nodes in the tree
represented by SEL_ARG's are OR conditions from where clause.
For each node, next_key_part will point to another RB tree
which is the AND condition present in the query along with
current node condition. ref_count in rb_tree/SEL_ARG represents
how many nodes are referring to this particular tree. Please
refer opt_range.cc for RB tree details.
Below explanation uses a simplified format for representing the tree.
Symbols used below are
--> => AND relation.
| => OR condition
[ Node Condition, Node Name, ref_count ] => Node format
Consider a query with where clause as:
(c1 = 1 AND c2 = 2) OR (c1 = 2 AND c2 = 1) OR
(c1 IN (3, 100) AND c2 = 10) OR (c1 IN (1, 2, 3) AND c2 = 2);
The resulting condition for this should be:
(c1 =1 AND c2 = 2) OR (c1 = 2 AND c2 = 1) OR
(c1 = 3 AND c2= 10) OR (c1 = 100 AND c2 = 10) OR
(c1= 1 AND c2 = 2) OR (c1=2 AND c2=2) OR (c1=3 AND c2=2)
First part of the where clause:
[ (c1 = 1 AND c2 = 2) OR (c1 = 2 AND c2 = 1) OR (c1 IN (3, 100) AND c2 = 10) ]
will result in below RB tree
First time when we OR, we get
[c1=1, D, 1] --> [c2=2, C, 1]
|
v
[c1=2, A, 0] --> [c2=1, B, 1]
Second time we OR, we get [Tree 1]
[c1=1, D, 1] --> [c2=2, C, 1]
|
|
[c1=2, A, 0] --> [c2=1, B, 1]
|
|
[c1=3, E, 0] --> [c2=10, G, 2]
| ^
| /
[c1=100, F, 0]
Rest of the condition [ (c1 IN (1, 2, 3) AND c2 = 2) ] will
result in below tree formation [Tree 2]
[c1=1, I, 1]
| \
| v
[c1=2, H, 0] --> [c2=2, K, 3]
| ^
| /
[c1=3, J, 0]
Below steps are performed while doing tree_or between these two trees.
Step 1. Take the first node from Tree.2 (Node I) and try to insert
into tree 1. As there is an exact match found in Tree 1 (Node D),
this node will be ignored and will be deleted from Tree 2.
As part of the delete operation, increment_use_count() for the
deleted node will be called with -1. This function will reduce ref_count
of next_key_part of all nodes in the current tree. As a result,
ref_count of Node.K will be reduced 3 times (one for Node H, I, J).
Resulting [Tree 2] will look like below
[c1 = 2, H, 1]
| \
| v
[C1 = 3, J, 0] --> [c2 = 2, K, 0]
Step 2. Node H will be merged with Node A. Steps to merge
these nodes are; As the condition is exactly same, it will
copy next key part of H and merge with B. If the next key part
node (Node K) ref_count is more than 1 then a copy is made
to avoid any unwanted links. In this case, it is (0) not more
than 1 and Node.K will be added as an OR element to Node.B.
Resulting Tree 1 will look like below.
[c1=1, D, 1] --> [c2=2, C, 1]
|
|
[c1=2, A, 0] --> [c2=1, B, 1]
| |
| |
| [c2=2, K, 0] <-- [c1=3, J, 0]
|
[c1=3, E, 0] --> [c2=10, G, 2]
| ^
| /
[c1=100, F, 0]
Note that Node.J is attached to Tree 1 now. Which is an unwanted
consequence of the ref_count reduction of Node.K 3 times at step 1.
Step 3: Node J will be merged with node E. Similar to above case,
node conditions are exactly same, so next_key_part merge will happen.
Like above scenario Node.K ref_count is not more than 1, so no
copy will be made but a copy of G will be made (Node H)(due to
ref_count = 2) and together attached to node E.
Resulting tree will look like below.
[c1=1, D, 1] --> [c2=2, C, 1]
|
|
[c1=2, A, 0] --> [c2=1, B, 1]
| |
| |
| [c2=2, K, 0]
| |
| |
[c1=3, E, 0] --> [c2=10, H, 2]
|
|
[c1=100, F, 0] --> [c2=10, G, 2]
As a result of above tree, few new conditions are possible. Which
were not present in orginal querry. Example,
Consider link C1 = 2 and (C2 = 1 or C2 = 2 or c2 = 10) from above tree.
In this, condition (c1 = 2 and c2 = 10) was not present in orginal query.
This will result in wrong estimate as it accounts for the
newly formed possibilities as well and results in wrong plan.
Issue that caused server exit is due to Node.H insertion to
Node K will result in undecided result as node K suppose to
be the root of the tree and which not the case here due to its
link with B as a consequence of the wrong ref_count of Node.K.
Solution: During node deletion in tree_or, reduce ref_count
of next key_part only once instead of one for each node in the tree.
0 commit comments