Switching [EXPLAIN] UPDATE/DELETE to rely on query plan footprints.
This requires that subselect's footprints are saved before it is deleted. Attempt to save select's QPF exposes one to a variety of edge cases: - the select may be a UNION's "fake select" which has no valid id - optimization may fail in the middle (but subsequent JOIN::optimize() calls will succeed, despite the fact that there never was a query plan)
This commit is contained in:
parent
52cfa54c1d
commit
ab4a13b2b9
@ -4341,7 +4341,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output)
|
|||||||
if (!first->next_select())
|
if (!first->next_select())
|
||||||
{
|
{
|
||||||
/* This is a 1-way UNION, i.e. not really a UNION */
|
/* This is a 1-way UNION, i.e. not really a UNION */
|
||||||
first->save_qpf(output);
|
if (!output->get_select(first->select_number))
|
||||||
|
first->save_qpf(output);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4371,7 +4372,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output)
|
|||||||
|
|
||||||
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
|
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
|
||||||
{
|
{
|
||||||
sl->save_qpf(output);
|
if (!output->get_select(sl->select_number))
|
||||||
|
sl->save_qpf(output);
|
||||||
qpfu->add_select(sl->select_number);
|
qpfu->add_select(sl->select_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,17 +1005,26 @@ err:
|
|||||||
|
|
||||||
int JOIN::optimize()
|
int JOIN::optimize()
|
||||||
{
|
{
|
||||||
|
bool was_optimized= optimized;
|
||||||
int res= optimize_inner();
|
int res= optimize_inner();
|
||||||
/*
|
/*
|
||||||
If we're inside a non-correlated subquery, this function may be
|
If we're inside a non-correlated subquery, this function may be
|
||||||
called for the second time after the subquery has been executed
|
called for the second time after the subquery has been executed
|
||||||
and deleted. The second call will not produce a valid query plan, it will
|
and deleted. The second call will not produce a valid query plan, it will
|
||||||
short-circuit because optimized==TRUE.
|
short-circuit because optimized==TRUE.
|
||||||
|
|
||||||
|
"was_optimized != optimized" is here to handle this case:
|
||||||
|
- first optimization starts, gets an error (from a const. cheap
|
||||||
|
subquery), returns 1
|
||||||
|
- another JOIN::optimize() call made, and now join->optimize() will
|
||||||
|
return 0, even though we never had a query plan.
|
||||||
*/
|
*/
|
||||||
if (!res && have_query_plan != QEP_DELETED)
|
if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED)
|
||||||
have_query_plan= QEP_AVAILABLE;
|
have_query_plan= QEP_AVAILABLE;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
global select optimisation.
|
global select optimisation.
|
||||||
|
|
||||||
@ -2301,7 +2310,6 @@ void JOIN::exec()
|
|||||||
select_lex->select_number))
|
select_lex->select_number))
|
||||||
dbug_serve_apcs(thd, 1);
|
dbug_serve_apcs(thd, 1);
|
||||||
);
|
);
|
||||||
|
|
||||||
thd->apc_target.disable();
|
thd->apc_target.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11099,7 +11107,33 @@ void JOIN::cleanup(bool full)
|
|||||||
DBUG_PRINT("enter", ("full %u", (uint) full));
|
DBUG_PRINT("enter", ("full %u", (uint) full));
|
||||||
|
|
||||||
if (full)
|
if (full)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
if (select_lex->select_number != UINT_MAX &&
|
||||||
|
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
|
||||||
|
have_query_plan != QEP_NOT_PRESENT_YET &&
|
||||||
|
!thd->lex->query_plan_footprint->get_select(select_lex->select_number))
|
||||||
|
{
|
||||||
|
const char *message= NULL;
|
||||||
|
|
||||||
|
if (!table_count || !tables_list || zero_result_cause)
|
||||||
|
{
|
||||||
|
/* It's a degenerate join */
|
||||||
|
message= zero_result_cause ? zero_result_cause : "No tables used";
|
||||||
|
}
|
||||||
|
|
||||||
|
save_qpf(thd->lex->query_plan_footprint,
|
||||||
|
need_tmp, // need_tmp_table
|
||||||
|
!skip_sort_order && !no_order &&
|
||||||
|
(order || group_list), // bool need_order
|
||||||
|
select_distinct, // bool distinct
|
||||||
|
message); // message
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
have_query_plan= QEP_DELETED; //psergey: this is a problem!
|
have_query_plan= QEP_DELETED; //psergey: this is a problem!
|
||||||
|
}
|
||||||
|
|
||||||
if (table)
|
if (table)
|
||||||
{
|
{
|
||||||
|
@ -1462,12 +1462,6 @@ public:
|
|||||||
{
|
{
|
||||||
return (unit->item && unit->item->is_in_predicate());
|
return (unit->item && unit->item->is_in_predicate());
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
int print_explain(select_result_sink *result, uint8 explain_flags,
|
|
||||||
bool on_the_fly,
|
|
||||||
bool need_tmp_table, bool need_order,
|
|
||||||
bool distinct,const char *message);
|
|
||||||
*/
|
|
||||||
int save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
|
int save_qpf(QPF_query *output, bool need_tmp_table, bool need_order,
|
||||||
bool distinct, const char *message);
|
bool distinct, const char *message);
|
||||||
private:
|
private:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user