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:
Sergey Petrunya 2013-06-20 22:30:30 +04:00
parent 52cfa54c1d
commit ab4a13b2b9
3 changed files with 40 additions and 10 deletions

View File

@ -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);
} }

View File

@ -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)
{ {

View File

@ -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: