1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-21383: Possible range plan is not used under certain conditions

[Variant 2 of the fix: collect the attached conditions]

Problem:
make_join_select() has a section of code which starts with
 "We plan to scan all rows. Check again if we should use an index."

the code in that section will [unnecessarily] re-run the range
optimizer using this condition:

  condition_attached_to_current_table AND current_table's_ON_expr

Note that the original invocation of range optimizer in
make_join_statistics was done using the whole select's WHERE condition.
Taking the whole select's WHERE condition and using multiple-equalities
allowed the range optimizer to infer more range restrictions.

The fix:
- Do range optimization using a condition that is an AND of this table's
condition and all of the previous tables' conditions.
- Also, fix the range optimizer to prefer SEL_ARGs with type=KEY_RANGE
over SEL_ARGS with type=MAYBE_KEY, regardless of the key part.
Computing
key_and(
  SEL_ARG(type=MAYBE_KEY key_part=1),
  SEL_ARG(type=KEY_RANGE, key_part=2)
)
will now produce the SEL_ARG with type=KEY_RANGE.
This commit is contained in:
Sergei Petrunia
2020-01-20 00:06:51 +03:00
parent ade89fc898
commit 7e8a58020b
4 changed files with 194 additions and 1 deletions

View File

@ -10543,6 +10543,74 @@ make_outerjoin_info(JOIN *join)
}
/*
@brief
Build a temporary join prefix condition for JOIN_TABs up to the last tab
@param ret OUT the condition is returned here
@return
false OK
true Out of memory
@detail
Walk through the join prefix (from the first table to the last_tab) and
build a condition:
join_tab_1_cond AND join_tab_2_cond AND ... AND last_tab_conds
The condition is only intended to be used by the range optimizer, so:
- it is not normalized (can have Item_cond_and inside another
Item_cond_and)
- it does not include join->exec_const_cond and other similar conditions.
*/
bool build_tmp_join_prefix_cond(JOIN *join, JOIN_TAB *last_tab, Item **ret)
{
THD *const thd= join->thd;
Item_cond_and *all_conds= NULL;
Item *res= NULL;
// Pick the ON-expression. Use the same logic as in get_sargable_cond():
if (last_tab->on_expr_ref)
res= *last_tab->on_expr_ref;
else if (last_tab->table->pos_in_table_list &&
last_tab->table->pos_in_table_list->embedding &&
!last_tab->table->pos_in_table_list->embedding->sj_on_expr)
{
res= last_tab->table->pos_in_table_list->embedding->on_expr;
}
for (JOIN_TAB *tab= first_depth_first_tab(join);
tab;
tab= next_depth_first_tab(join, tab))
{
if (tab->select_cond)
{
if (!res)
res= tab->select_cond;
else
{
if (!all_conds)
{
if (!(all_conds= new (thd->mem_root)Item_cond_and(thd, res,
tab->select_cond)))
return true;
res= all_conds;
}
else
all_conds->add(tab->select_cond, thd->mem_root);
}
}
if (tab == last_tab)
break;
}
*ret= all_conds? all_conds: res;
return false;
}
static bool
make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
@ -10890,7 +10958,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Join with outer join condition */
COND *orig_cond=sel->cond;
sel->cond= and_conds(thd, sel->cond, *tab->on_expr_ref);
if (build_tmp_join_prefix_cond(join, tab, &sel->cond))
return true;
/*
We can't call sel->cond->fix_fields,