mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-27510 Query returns wrong result when using split optimization
This bug may affect the queries that uses a grouping derived table with grouping list containing references to columns from different tables if the optimizer decides to employ the split optimization for the derived table. In some very specific cases it may affect queries with a grouping derived table that refers only one base table. This bug was caused by an improper fix for the bug MDEV-25128. The fix tried to get rid of the equality conditions pushed into the where clause of the grouping derived table T to which the split optimization had been applied. The fix erroneously assumed that only those pushed equalities that were used for ref access of the tables referenced by T were needed. In fact the function remove_const() that figures out what columns from the group list can be removed if the split optimization is applied can uses other pushed equalities as well. This patch actually provides a proper fix for MDEV-25128. Rather than trying to remove invalid pushed equalities referencing the fields of SJM tables with a look-up access the patch attempts not to push such equalities. Approved by Oleksandr Byelkin <sanja@mariadb.com>
This commit is contained in:
@ -1048,16 +1048,16 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count,
|
||||
Inject equalities for splitting used by the materialization join
|
||||
|
||||
@param
|
||||
remaining_tables used to filter out the equalities that cannot
|
||||
excluded_tables used to filter out the equalities that cannot
|
||||
be pushed.
|
||||
|
||||
@details
|
||||
This function is called by JOIN_TAB::fix_splitting that is used
|
||||
to fix the chosen splitting of a splittable materialized table T
|
||||
in the final query execution plan. In this plan the table T
|
||||
is joined just before the 'remaining_tables'. So all equalities
|
||||
usable for splitting whose right parts do not depend on any of
|
||||
remaining tables can be pushed into join for T.
|
||||
This function injects equalities pushed into a derived table T for which
|
||||
the split optimization has been chosen by the optimizer. The function
|
||||
is called by JOIN::inject_splitting_cond_for_all_tables_with_split_op().
|
||||
All equalities usable for splitting T whose right parts do not depend on
|
||||
any of the 'excluded_tables' can be pushed into the where clause of the
|
||||
derived table T.
|
||||
The function also marks the select that specifies T as
|
||||
UNCACHEABLE_DEPENDENT_INJECTED.
|
||||
|
||||
@ -1066,7 +1066,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count,
|
||||
true on failure
|
||||
*/
|
||||
|
||||
bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
|
||||
bool JOIN::inject_best_splitting_cond(table_map excluded_tables)
|
||||
{
|
||||
Item *inj_cond= 0;
|
||||
List<Item> *inj_cond_list= &spl_opt_info->inj_cond_list;
|
||||
@ -1074,7 +1074,7 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
|
||||
KEY_FIELD *added_key_field;
|
||||
while ((added_key_field= li++))
|
||||
{
|
||||
if (remaining_tables & added_key_field->val->used_tables())
|
||||
if (excluded_tables & added_key_field->val->used_tables())
|
||||
continue;
|
||||
if (inj_cond_list->push_back(added_key_field->cond, thd->mem_root))
|
||||
return true;
|
||||
@ -1168,8 +1168,6 @@ bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan,
|
||||
memcpy((char *) md_join->best_positions,
|
||||
(char *) spl_plan->best_positions,
|
||||
sizeof(POSITION) * md_join->table_count);
|
||||
if (md_join->inject_best_splitting_cond(remaining_tables))
|
||||
return true;
|
||||
/*
|
||||
This is called for a proper work of JOIN::get_best_combination()
|
||||
called for the join that materializes T
|
||||
@ -1213,7 +1211,8 @@ bool JOIN::fix_all_splittings_in_plan()
|
||||
if (tab->table->is_splittable())
|
||||
{
|
||||
SplM_plan_info *spl_plan= cur_pos->spl_plan;
|
||||
if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables,
|
||||
if (tab->fix_splitting(spl_plan,
|
||||
all_tables & ~prev_tables,
|
||||
tablenr < const_tables ))
|
||||
return true;
|
||||
}
|
||||
@ -1221,3 +1220,44 @@ bool JOIN::fix_all_splittings_in_plan()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
Inject splitting conditions into WHERE of split derived
|
||||
|
||||
@details
|
||||
The function calls JOIN_TAB::inject_best_splitting_cond() for each
|
||||
materialized derived table T used in this join for which the split
|
||||
optimization has been chosen by the optimizer. It is done in order to
|
||||
inject equalities pushed into the where clause of the specification
|
||||
of T that would be helpful to employ the splitting technique.
|
||||
|
||||
@retval
|
||||
false on success
|
||||
true on failure
|
||||
*/
|
||||
|
||||
bool JOIN::inject_splitting_cond_for_all_tables_with_split_opt()
|
||||
{
|
||||
table_map prev_tables= 0;
|
||||
table_map all_tables= (table_map(1) << table_count) - 1;
|
||||
for (uint tablenr= 0; tablenr < table_count; tablenr++)
|
||||
{
|
||||
POSITION *cur_pos= &best_positions[tablenr];
|
||||
JOIN_TAB *tab= cur_pos->table;
|
||||
prev_tables|= tab->table->map;
|
||||
if (!(tab->table->is_splittable() && cur_pos->spl_plan))
|
||||
continue;
|
||||
SplM_opt_info *spl_opt_info= tab->table->spl_opt_info;
|
||||
JOIN *join= spl_opt_info->join;
|
||||
/*
|
||||
Currently the equalities referencing columns of SJM tables with
|
||||
look-up access cannot be pushed into materialized derived.
|
||||
*/
|
||||
if (join->inject_best_splitting_cond((all_tables & ~prev_tables) |
|
||||
sjm_lookup_tables))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Reference in New Issue
Block a user