[SHOW] EXPLAIN UPDATE/DELETE, code re-structuring
Single table UPDATE/DELETE - Correctly print type=SIMPLE vs type=PRIMARY - Handle UPDATE/DELETE of mergeable VIEWs: we get the VIEW's select as the first subquery. (MySQL 5.6 doesn't print it because it finds that the subquery is not attached to any select)
This commit is contained in:
parent
0a560289aa
commit
52cfa54c1d
@ -1,4 +1,4 @@
|
|||||||
drop table if exists t0;
|
drop table if exists t0, t1;
|
||||||
create table t0 (a int) engine=myisam;
|
create table t0 (a int) engine=myisam;
|
||||||
insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
|
insert into t0 values (1),(2),(3),(4),(5),(6),(7),(8);
|
||||||
#
|
#
|
||||||
|
@ -49,6 +49,7 @@ void QPF_query::add_node(QPF_node *node)
|
|||||||
if (node->get_type() == QPF_node::QPF_UNION)
|
if (node->get_type() == QPF_node::QPF_UNION)
|
||||||
{
|
{
|
||||||
QPF_union *u= (QPF_union*)node;
|
QPF_union *u= (QPF_union*)node;
|
||||||
|
DBUG_ASSERT(!unions[u->get_select_id()]);
|
||||||
unions[u->get_select_id()]= u;
|
unions[u->get_select_id()]= u;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -60,7 +61,10 @@ void QPF_query::add_node(QPF_node *node)
|
|||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!selects[sel->select_id]);
|
||||||
selects[sel->select_id] = sel;
|
selects[sel->select_id] = sel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +497,7 @@ int QPF_delete::print_explain(QPF_query *query, select_result_sink *output,
|
|||||||
const char *msg= "Deleting all rows";
|
const char *msg= "Deleting all rows";
|
||||||
int res= print_explain_message_line(output, explain_flags,
|
int res= print_explain_message_line(output, explain_flags,
|
||||||
1 /*select number*/,
|
1 /*select number*/,
|
||||||
"SIMPLE", msg);
|
select_type, msg);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -513,7 +517,7 @@ int QPF_update::print_explain(QPF_query *query, select_result_sink *output,
|
|||||||
const char *msg= "Impossible where";
|
const char *msg= "Impossible where";
|
||||||
int res= print_explain_message_line(output, explain_flags,
|
int res= print_explain_message_line(output, explain_flags,
|
||||||
1 /*select number*/,
|
1 /*select number*/,
|
||||||
"SIMPLE", msg);
|
select_type, msg);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,7 +545,7 @@ int QPF_update::print_explain(QPF_query *query, select_result_sink *output,
|
|||||||
|
|
||||||
print_explain_row(output, explain_flags,
|
print_explain_row(output, explain_flags,
|
||||||
1, /* id */
|
1, /* id */
|
||||||
"SIMPLE",
|
select_type,
|
||||||
table_name.c_ptr(),
|
table_name.c_ptr(),
|
||||||
// partitions,
|
// partitions,
|
||||||
jtype,
|
jtype,
|
||||||
|
@ -350,6 +350,8 @@ public:
|
|||||||
virtual enum qpf_node_type get_type() { return QPF_UPDATE; }
|
virtual enum qpf_node_type get_type() { return QPF_UPDATE; }
|
||||||
virtual int get_select_id() { return 1; /* always root */ }
|
virtual int get_select_id() { return 1; /* always root */ }
|
||||||
|
|
||||||
|
const char *select_type;
|
||||||
|
|
||||||
bool impossible_where;
|
bool impossible_where;
|
||||||
StringBuffer<64> table_name;
|
StringBuffer<64> table_name;
|
||||||
|
|
||||||
|
@ -58,10 +58,12 @@ void Delete_plan::save_query_plan_footprint(QPF_query *query)
|
|||||||
if (deleting_all_rows)
|
if (deleting_all_rows)
|
||||||
{
|
{
|
||||||
qpf->deleting_all_rows= true;
|
qpf->deleting_all_rows= true;
|
||||||
|
qpf->select_type= "SIMPLE";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Update_plan::save_query_plan_footprint_intern(qpf);
|
qpf->deleting_all_rows= false;
|
||||||
|
Update_plan::save_query_plan_footprint_intern(query, qpf);
|
||||||
}
|
}
|
||||||
|
|
||||||
query->upd_del_plan= qpf;
|
query->upd_del_plan= qpf;
|
||||||
@ -71,13 +73,14 @@ void Delete_plan::save_query_plan_footprint(QPF_query *query)
|
|||||||
void Update_plan::save_query_plan_footprint(QPF_query *query)
|
void Update_plan::save_query_plan_footprint(QPF_query *query)
|
||||||
{
|
{
|
||||||
QPF_update* qpf= new QPF_update;
|
QPF_update* qpf= new QPF_update;
|
||||||
save_query_plan_footprint_intern(qpf);
|
save_query_plan_footprint_intern(query, qpf);
|
||||||
query->upd_del_plan= qpf;
|
query->upd_del_plan= qpf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Update_plan::save_query_plan_footprint_intern(QPF_update *qpf)
|
void Update_plan::save_query_plan_footprint_intern(QPF_query *query, QPF_update *qpf)
|
||||||
{
|
{
|
||||||
|
qpf->select_type= "SIMPLE";
|
||||||
qpf->table_name.append(table->pos_in_table_list->alias);
|
qpf->table_name.append(table->pos_in_table_list->alias);
|
||||||
if (impossible_where)
|
if (impossible_where)
|
||||||
{
|
{
|
||||||
@ -85,8 +88,10 @@ void Update_plan::save_query_plan_footprint_intern(QPF_update *qpf)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do we need the following: select_type
|
qpf->impossible_where= false;
|
||||||
//select_lex->set_explain_type(TRUE);
|
|
||||||
|
select_lex->set_explain_type(TRUE);
|
||||||
|
qpf->select_type= select_lex->type;
|
||||||
|
|
||||||
/* Set jtype */
|
/* Set jtype */
|
||||||
if (select && select->quick)
|
if (select && select->quick)
|
||||||
@ -134,6 +139,28 @@ void Update_plan::save_query_plan_footprint_intern(QPF_update *qpf)
|
|||||||
{
|
{
|
||||||
explain_append_mrr_info((QUICK_RANGE_SELECT*)select->quick, &qpf->mrr_type);
|
explain_append_mrr_info((QUICK_RANGE_SELECT*)select->quick, &qpf->mrr_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool skip= updating_a_view;
|
||||||
|
/* Save subquery children */
|
||||||
|
for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit();
|
||||||
|
unit;
|
||||||
|
unit= unit->next_unit())
|
||||||
|
{
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
skip= false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Display subqueries only if they are not parts of eliminated WHERE/ON
|
||||||
|
clauses.
|
||||||
|
*/
|
||||||
|
if (!(unit->item && unit->item->eliminated))
|
||||||
|
qpf->add_child(unit->first_select()->select_number);
|
||||||
|
|
||||||
|
//TODO: temporary?:
|
||||||
|
unit->save_qpf(query);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -194,6 +221,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||||||
query_plan.select_lex= &thd->lex->select_lex;
|
query_plan.select_lex= &thd->lex->select_lex;
|
||||||
query_plan.table= table;
|
query_plan.table= table;
|
||||||
|
|
||||||
|
//psergey-todo: Ugly, discuss with Sanja
|
||||||
|
query_plan.updating_a_view= test(table_list->view);
|
||||||
|
|
||||||
if (mysql_prepare_delete(thd, table_list, &conds))
|
if (mysql_prepare_delete(thd, table_list, &conds))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
@ -612,7 +642,7 @@ exit_without_my_ok:
|
|||||||
List<Item> dummy; /* note: looked in 5.6 and they too use a dummy list like this */
|
List<Item> dummy; /* note: looked in 5.6 and they too use a dummy list like this */
|
||||||
result->prepare(dummy, &thd->lex->unit);
|
result->prepare(dummy, &thd->lex->unit);
|
||||||
thd->send_explain_fields(result);
|
thd->send_explain_fields(result);
|
||||||
int err2= thd->lex->query_plan_footprint->print_explain(result, 0);
|
int err2= thd->lex->query_plan_footprint->print_explain(result, 0 /* explain flags*/);
|
||||||
|
|
||||||
if (err2)
|
if (err2)
|
||||||
result->abort_result_set();
|
result->abort_result_set();
|
||||||
|
@ -4337,6 +4337,13 @@ int st_select_lex_unit::save_qpf(QPF_query *output)
|
|||||||
{
|
{
|
||||||
//int res= 0;
|
//int res= 0;
|
||||||
SELECT_LEX *first= first_select();
|
SELECT_LEX *first= first_select();
|
||||||
|
|
||||||
|
if (!first->next_select())
|
||||||
|
{
|
||||||
|
/* This is a 1-way UNION, i.e. not really a UNION */
|
||||||
|
first->save_qpf(output);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
QPF_union *qpfu= new QPF_union;
|
QPF_union *qpfu= new QPF_union;
|
||||||
/*
|
/*
|
||||||
|
@ -730,10 +730,7 @@ public:
|
|||||||
friend int subselect_union_engine::exec();
|
friend int subselect_union_engine::exec();
|
||||||
|
|
||||||
List<Item> *get_unit_column_types();
|
List<Item> *get_unit_column_types();
|
||||||
#if 0
|
|
||||||
int print_explain(select_result_sink *output, uint8 explain_flags,
|
|
||||||
bool *printed_anything);
|
|
||||||
#endif
|
|
||||||
int save_qpf(QPF_query *output);
|
int save_qpf(QPF_query *output);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2379,6 +2376,7 @@ class Update_plan
|
|||||||
protected:
|
protected:
|
||||||
bool impossible_where;
|
bool impossible_where;
|
||||||
public:
|
public:
|
||||||
|
bool updating_a_view;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
SQL_SELECT *select;
|
SQL_SELECT *select;
|
||||||
uint index;
|
uint index;
|
||||||
@ -2396,7 +2394,7 @@ public:
|
|||||||
void set_impossible_where() { impossible_where= true; }
|
void set_impossible_where() { impossible_where= true; }
|
||||||
|
|
||||||
void save_query_plan_footprint(QPF_query *query);
|
void save_query_plan_footprint(QPF_query *query);
|
||||||
void save_query_plan_footprint_intern(QPF_update *qpf);
|
void save_query_plan_footprint_intern(QPF_query *query, QPF_update *qpf);
|
||||||
virtual ~Update_plan() {}
|
virtual ~Update_plan() {}
|
||||||
|
|
||||||
Update_plan() : impossible_where(false), using_filesort(false) {}
|
Update_plan() : impossible_where(false), using_filesort(false) {}
|
||||||
|
@ -314,6 +314,10 @@ int mysql_update(THD *thd,
|
|||||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
|
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//psergey-todo: Ugly, discuss with Sanja
|
||||||
|
query_plan.updating_a_view= test(table_list->view);
|
||||||
|
|
||||||
/* Calculate "table->covering_keys" based on the WHERE */
|
/* Calculate "table->covering_keys" based on the WHERE */
|
||||||
table->covering_keys= table->s->keys_in_use;
|
table->covering_keys= table->s->keys_in_use;
|
||||||
table->quick_keys.clear_all();
|
table->quick_keys.clear_all();
|
||||||
@ -1013,13 +1017,14 @@ exit_without_my_ok:
|
|||||||
query_plan.save_query_plan_footprint(thd->lex->query_plan_footprint);
|
query_plan.save_query_plan_footprint(thd->lex->query_plan_footprint);
|
||||||
|
|
||||||
select_send *result;
|
select_send *result;
|
||||||
bool printed_anything;
|
//bool printed_anything;
|
||||||
if (!(result= new select_send()))
|
if (!(result= new select_send()))
|
||||||
return 1; /* purecov: inspected */
|
return 1; /* purecov: inspected */
|
||||||
List<Item> dummy; /* note: looked in 5.6 and they too use a dummy list like this */
|
List<Item> dummy; /* note: looked in 5.6 and they too use a dummy list like this */
|
||||||
result->prepare(dummy, &thd->lex->unit);
|
result->prepare(dummy, &thd->lex->unit);
|
||||||
thd->send_explain_fields(result);
|
thd->send_explain_fields(result);
|
||||||
int err2= thd->lex->print_explain(result, 0 /* explain flags*/, &printed_anything);
|
//int err2= thd->lex->print_explain(result, 0 /* explain flags*/, &printed_anything);
|
||||||
|
int err2= thd->lex->query_plan_footprint->print_explain(result, 0 /* explain flags*/);
|
||||||
|
|
||||||
if (err2)
|
if (err2)
|
||||||
result->abort_result_set();
|
result->abort_result_set();
|
||||||
@ -1498,6 +1503,7 @@ bool mysql_multi_update(THD *thd,
|
|||||||
{
|
{
|
||||||
if (explain)
|
if (explain)
|
||||||
{
|
{
|
||||||
|
thd->lex->query_plan_footprint->print_explain(output, 0);
|
||||||
output->send_eof();
|
output->send_eof();
|
||||||
delete output;
|
delete output;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user