Commit 105e3ae6 authored by Sergey Petrunya's avatar Sergey Petrunya

MDEV-3798: EXPLAIN UPDATE/DELETE

Update the SHOW EXPLAIN code to work with the 
new architecture (part#1):
Before, SHOW EXPLAIN operated on real query plan structures, 
which meant it had to check when SELECTs are created/deleted.
SELECTs would call apc_target->enable() when they got a query 
plan and disable() when their query plan was deleted.

Now, Explain data structure becomes available at once (and we
call apc_target->enable()) and then it stays until it is deleted
(when that happens, we call apc_target->disable()).


parent f67f8fd0
...@@ -181,6 +181,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_start'; ...@@ -181,6 +181,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_start';
set @foo= (select max(a) from t0 where sin(a) >0); set @foo= (select max(a) from t0 where sin(a) >0);
show explain for $thr2; show explain for $thr2;
ERROR HY000: Target is not running an EXPLAINable command ERROR HY000: Target is not running an EXPLAINable command
kill query $thr2;
ERROR 70100: Query execution was interrupted
set debug_dbug=@old_debug; set debug_dbug=@old_debug;
# #
# Attempt SHOW EXPLAIN for an UPDATE # Attempt SHOW EXPLAIN for an UPDATE
...@@ -405,13 +407,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_end'; ...@@ -405,13 +407,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_end';
SELECT * FROM v1, t2; SELECT * FROM v1, t2;
show explain for $thr2; show explain for $thr2;
ERROR HY000: Target is not running an EXPLAINable command ERROR HY000: Target is not running an EXPLAINable command
a b kill query $thr2;
8 4 ERROR 70100: Query execution was interrupted
8 5
8 6
8 7
8 8
8 9
set debug_dbug=@old_debug; set debug_dbug=@old_debug;
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t2, t3; DROP TABLE t2, t3;
......
...@@ -224,7 +224,9 @@ connection default; ...@@ -224,7 +224,9 @@ connection default;
--source include/wait_condition.inc --source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE --error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2; evalp show explain for $thr2;
evalp kill query $thr2;
connection con1; connection con1;
--error ER_QUERY_INTERRUPTED
reap; reap;
set debug_dbug=@old_debug; set debug_dbug=@old_debug;
...@@ -399,7 +401,9 @@ connection default; ...@@ -399,7 +401,9 @@ connection default;
--source include/wait_condition.inc --source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE --error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2; evalp show explain for $thr2;
evalp kill query $thr2;
connection con1; connection con1;
--error ER_QUERY_INTERRUPTED
reap; reap;
set debug_dbug=@old_debug; set debug_dbug=@old_debug;
DROP VIEW v1; DROP VIEW v1;
......
...@@ -3037,7 +3037,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, ...@@ -3037,7 +3037,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
else if (! thd->in_sub_stmt) else if (! thd->in_sub_stmt)
thd->mdl_context.release_statement_locks(); thd->mdl_context.release_statement_locks();
} }
//TODO: why is this here if log_slow_query is in sp_instr_stmt_execute?
delete_explain_query(m_lex); delete_explain_query(m_lex);
if (m_lex->query_tables_own_last) if (m_lex->query_tables_own_last)
......
...@@ -66,8 +66,8 @@ void Delete_plan::save_explain_data(Explain_query *query) ...@@ -66,8 +66,8 @@ void Delete_plan::save_explain_data(Explain_query *query)
explain->deleting_all_rows= false; explain->deleting_all_rows= false;
Update_plan::save_explain_data_intern(query, explain); Update_plan::save_explain_data_intern(query, explain);
} }
query->upd_del_plan= explain; query->add_upd_del_plan(explain);
} }
...@@ -75,7 +75,7 @@ void Update_plan::save_explain_data(Explain_query *query) ...@@ -75,7 +75,7 @@ void Update_plan::save_explain_data(Explain_query *query)
{ {
Explain_update* explain= new Explain_update; Explain_update* explain= new Explain_update;
save_explain_data_intern(query, explain); save_explain_data_intern(query, explain);
query->upd_del_plan= explain; query->add_upd_del_plan(explain);
} }
...@@ -459,7 +459,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -459,7 +459,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
goto exit_without_my_ok; goto exit_without_my_ok;
query_plan.save_explain_data(thd->lex->explain); query_plan.save_explain_data(thd->lex->explain);
thd->apc_target.enable();
DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start", DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",
dbug_serve_apcs(thd, 1);); dbug_serve_apcs(thd, 1););
...@@ -486,7 +485,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -486,7 +485,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{ {
delete select; delete select;
free_underlaid_joins(thd, &thd->lex->select_lex); free_underlaid_joins(thd, &thd->lex->select_lex);
thd->apc_target.disable();
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
thd->examined_row_count+= examined_rows; thd->examined_row_count+= examined_rows;
...@@ -505,7 +503,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -505,7 +503,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{ {
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
thd->apc_target.disable();
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (query_plan.index == MAX_KEY || (select && select->quick)) if (query_plan.index == MAX_KEY || (select && select->quick))
...@@ -514,7 +511,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -514,7 +511,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{ {
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
thd->apc_target.disable();
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
} }
...@@ -624,7 +620,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -624,7 +620,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK) if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL); (void) table->file->extra(HA_EXTRA_NORMAL);
thd->apc_target.disable();
cleanup: cleanup:
/* /*
Invalidate the table in the query cache if something changed. This must Invalidate the table in the query cache if something changed. This must
......
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
#include "sql_select.h" #include "sql_select.h"
Explain_query::Explain_query() : upd_del_plan(NULL), insert_plan(NULL) Explain_query::Explain_query(THD *thd_arg) :
upd_del_plan(NULL), insert_plan(NULL), thd(thd_arg), apc_enabled(false)
{ {
operations= 0; operations= 0;
} }
...@@ -30,6 +31,9 @@ Explain_query::Explain_query() : upd_del_plan(NULL), insert_plan(NULL) ...@@ -30,6 +31,9 @@ Explain_query::Explain_query() : upd_del_plan(NULL), insert_plan(NULL)
Explain_query::~Explain_query() Explain_query::~Explain_query()
{ {
if (apc_enabled)
thd->apc_target.disable();
delete upd_del_plan; delete upd_del_plan;
delete insert_plan; delete insert_plan;
uint i; uint i;
...@@ -62,11 +66,12 @@ Explain_select *Explain_query::get_select(uint select_id) ...@@ -62,11 +66,12 @@ Explain_select *Explain_query::get_select(uint select_id)
void Explain_query::add_node(Explain_node *node) void Explain_query::add_node(Explain_node *node)
{ {
uint select_id;
operations++; operations++;
if (node->get_type() == Explain_node::EXPLAIN_UNION) if (node->get_type() == Explain_node::EXPLAIN_UNION)
{ {
Explain_union *u= (Explain_union*)node; Explain_union *u= (Explain_union*)node;
uint select_id= u->get_select_id(); select_id= u->get_select_id();
if (unions.elements() <= select_id) if (unions.elements() <= select_id)
unions.resize(max(select_id+1, unions.elements()*2), NULL); unions.resize(max(select_id+1, unions.elements()*2), NULL);
...@@ -85,7 +90,7 @@ void Explain_query::add_node(Explain_node *node) ...@@ -85,7 +90,7 @@ void Explain_query::add_node(Explain_node *node)
} }
else else
{ {
uint select_id= sel->select_id; select_id= sel->select_id;
Explain_select *old_node; Explain_select *old_node;
if (selects.elements() <= select_id) if (selects.elements() <= select_id)
...@@ -100,6 +105,27 @@ void Explain_query::add_node(Explain_node *node) ...@@ -100,6 +105,27 @@ void Explain_query::add_node(Explain_node *node)
} }
void Explain_query::add_insert_plan(Explain_insert *insert_plan_arg)
{
insert_plan= insert_plan_arg;
query_plan_ready();
}
void Explain_query::add_upd_del_plan(Explain_update *upd_del_plan_arg)
{
upd_del_plan= upd_del_plan_arg;
query_plan_ready();
}
void Explain_query::query_plan_ready()
{
if (!apc_enabled)
thd->apc_target.enable();
apc_enabled= true;
}
/* /*
Send EXPLAIN output to the client. Send EXPLAIN output to the client.
*/ */
...@@ -915,7 +941,7 @@ void delete_explain_query(LEX *lex) ...@@ -915,7 +941,7 @@ void delete_explain_query(LEX *lex)
void create_explain_query(LEX *lex, MEM_ROOT *mem_root) void create_explain_query(LEX *lex, MEM_ROOT *mem_root)
{ {
DBUG_ASSERT(!lex->explain); DBUG_ASSERT(!lex->explain);
lex->explain= new Explain_query; lex->explain= new Explain_query(lex->thd);
DBUG_ASSERT(mem_root == current_thd->mem_root); DBUG_ASSERT(mem_root == current_thd->mem_root);
lex->explain->mem_root= mem_root; lex->explain->mem_root= mem_root;
} }
......
...@@ -221,10 +221,13 @@ class Explain_insert; ...@@ -221,10 +221,13 @@ class Explain_insert;
class Explain_query : public Sql_alloc class Explain_query : public Sql_alloc
{ {
public: public:
Explain_query(); Explain_query(THD *thd);
~Explain_query(); ~Explain_query();
/* Add a new node */ /* Add a new node */
void add_node(Explain_node *node); void add_node(Explain_node *node);
void add_insert_plan(Explain_insert *insert_plan_arg);
void add_upd_del_plan(Explain_update *upd_del_plan_arg);
/* This will return a select, or a union */ /* This will return a select, or a union */
Explain_node *get_node(uint select_id); Explain_node *get_node(uint select_id);
...@@ -233,13 +236,7 @@ public: ...@@ -233,13 +236,7 @@ public:
Explain_select *get_select(uint select_id); Explain_select *get_select(uint select_id);
Explain_union *get_union(uint select_id); Explain_union *get_union(uint select_id);
/* Explain_delete inherits from Explain_update */
Explain_update *upd_del_plan;
/* Query "plan" for INSERTs */
Explain_insert *insert_plan;
/* Produce a tabular EXPLAIN output */ /* Produce a tabular EXPLAIN output */
int print_explain(select_result_sink *output, uint8 explain_flags); int print_explain(select_result_sink *output, uint8 explain_flags);
...@@ -251,11 +248,22 @@ public: ...@@ -251,11 +248,22 @@ public:
/* If true, at least part of EXPLAIN can be printed */ /* If true, at least part of EXPLAIN can be printed */
bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; } bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; }
void query_plan_ready();
MEM_ROOT *mem_root; MEM_ROOT *mem_root;
private: private:
/* Explain_delete inherits from Explain_update */
Explain_update *upd_del_plan;
/* Query "plan" for INSERTs */
Explain_insert *insert_plan;
Dynamic_array<Explain_union*> unions; Dynamic_array<Explain_union*> unions;
Dynamic_array<Explain_select*> selects; Dynamic_array<Explain_select*> selects;
THD *thd; // for APC start/stop
bool apc_enabled;
/* /*
Debugging aid: count how many times add_node() was called. Ideally, it Debugging aid: count how many times add_node() was called. Ideally, it
should be one, we currently allow O(1) query plan saves for each should be one, we currently allow O(1) query plan saves for each
......
...@@ -461,7 +461,8 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type, ...@@ -461,7 +461,8 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) || if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
thd->variables.max_insert_delayed_threads == 0 || thd->variables.max_insert_delayed_threads == 0 ||
thd->locked_tables_mode > LTM_LOCK_TABLES || thd->locked_tables_mode > LTM_LOCK_TABLES ||
thd->lex->uses_stored_routines()) thd->lex->uses_stored_routines() /*||
thd->lex->describe*/)
{ {
*lock_type= TL_WRITE; *lock_type= TL_WRITE;
return; return;
...@@ -649,7 +650,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list) ...@@ -649,7 +650,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
Explain_insert* explain= new Explain_insert; Explain_insert* explain= new Explain_insert;
explain->table_name.append(table_list->table->alias); explain->table_name.append(table_list->table->alias);
thd->lex->explain->insert_plan= explain; thd->lex->explain->add_insert_plan(explain);
/* See Update_plan::updating_a_view for details */ /* See Update_plan::updating_a_view for details */
bool skip= test(table_list->view); bool skip= test(table_list->view);
......
...@@ -4276,11 +4276,15 @@ int st_select_lex_unit::save_union_explain(Explain_query *output) ...@@ -4276,11 +4276,15 @@ int st_select_lex_unit::save_union_explain(Explain_query *output)
for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
eu->add_select(sl->select_number); eu->add_select(sl->select_number);
eu->fake_select_type= "UNION RESULT";
eu->using_filesort= test(global_parameters->order_list.first);
// Save the UNION node // Save the UNION node
output->add_node(eu); output->add_node(eu);
eu->fake_select_type= "UNION RESULT"; if (eu->get_select_id() == 1)
eu->using_filesort= test(global_parameters->order_list.first); output->query_plan_ready();
return 0; return 0;
} }
......
...@@ -1031,6 +1031,10 @@ public: ...@@ -1031,6 +1031,10 @@ public:
void clear_index_hints(void) { index_hints= NULL; } void clear_index_hints(void) { index_hints= NULL; }
bool is_part_of_union() { return master_unit()->is_union(); } bool is_part_of_union() { return master_unit()->is_union(); }
bool is_top_level_node()
{
return (select_number == 1) && !is_part_of_union();
}
bool optimize_unflattened_subqueries(bool const_only); bool optimize_unflattened_subqueries(bool const_only);
/* Set the EXPLAIN type for this subquery. */ /* Set the EXPLAIN type for this subquery. */
void set_explain_type(bool on_the_fly); void set_explain_type(bool on_the_fly);
......
...@@ -2298,8 +2298,6 @@ JOIN::save_join_tab() ...@@ -2298,8 +2298,6 @@ JOIN::save_join_tab()
void join_save_qpf(JOIN *join) void join_save_qpf(JOIN *join)
{ {
THD *thd= join->thd; THD *thd= join->thd;
//TODO: why not call st_select_lex::save_qpf here?
if (join->select_lex->select_number != UINT_MAX && if (join->select_lex->select_number != UINT_MAX &&
join->select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ && join->select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
join->have_query_plan != JOIN::QEP_NOT_PRESENT_YET && join->have_query_plan != JOIN::QEP_NOT_PRESENT_YET &&
...@@ -2315,7 +2313,7 @@ void join_save_qpf(JOIN *join) ...@@ -2315,7 +2313,7 @@ void join_save_qpf(JOIN *join)
/* It's a degenerate join */ /* It's a degenerate join */
message= join->zero_result_cause ? join->zero_result_cause : "No tables used"; message= join->zero_result_cause ? join->zero_result_cause : "No tables used";
} }
join->save_explain_data(thd->lex->explain, join->save_explain_data(thd->lex->explain,
join->need_tmp, join->need_tmp,
!join->skip_sort_order && !join->no_order && !join->skip_sort_order && !join->no_order &&
...@@ -2328,7 +2326,6 @@ void join_save_qpf(JOIN *join) ...@@ -2328,7 +2326,6 @@ void join_save_qpf(JOIN *join)
void JOIN::exec() void JOIN::exec()
{ {
thd->apc_target.enable();
DBUG_EXECUTE_IF("show_explain_probe_join_exec_start", DBUG_EXECUTE_IF("show_explain_probe_join_exec_start",
if (dbug_user_var_equals_int(thd, if (dbug_user_var_equals_int(thd,
"show_explain_probe_select_id", "show_explain_probe_select_id",
...@@ -2368,7 +2365,6 @@ void JOIN::exec() ...@@ -2368,7 +2365,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();
} }
...@@ -22997,6 +22993,10 @@ int JOIN::save_explain_data(Explain_query *output, bool need_tmp_table, ...@@ -22997,6 +22993,10 @@ int JOIN::save_explain_data(Explain_query *output, bool need_tmp_table,
} }
} }
if (!error && select_lex->is_top_level_node())
output->query_plan_ready();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -279,7 +279,6 @@ int mysql_update(THD *thd, ...@@ -279,7 +279,6 @@ int mysql_update(THD *thd,
Update_plan query_plan(thd->mem_root); Update_plan query_plan(thd->mem_root);
query_plan.index= MAX_KEY; query_plan.index= MAX_KEY;
query_plan.using_filesort= FALSE; query_plan.using_filesort= FALSE;
bool apc_target_enabled= false; // means was enabled *by code this function*
DBUG_ENTER("mysql_update"); DBUG_ENTER("mysql_update");
if (open_tables(thd, &table_list, &table_count, 0)) if (open_tables(thd, &table_list, &table_count, 0))
...@@ -518,8 +517,6 @@ int mysql_update(THD *thd, ...@@ -518,8 +517,6 @@ int mysql_update(THD *thd,
goto exit_without_my_ok; goto exit_without_my_ok;
query_plan.save_explain_data(thd->lex->explain); query_plan.save_explain_data(thd->lex->explain);
thd->apc_target.enable();
apc_target_enabled= true;
DBUG_EXECUTE_IF("show_explain_probe_update_exec_start", DBUG_EXECUTE_IF("show_explain_probe_update_exec_start",
dbug_serve_apcs(thd, 1);); dbug_serve_apcs(thd, 1););
...@@ -960,8 +957,6 @@ int mysql_update(THD *thd, ...@@ -960,8 +957,6 @@ int mysql_update(THD *thd,
if (!transactional_table && updated > 0) if (!transactional_table && updated > 0)
thd->transaction.stmt.modified_non_trans_table= TRUE; thd->transaction.stmt.modified_non_trans_table= TRUE;
thd->apc_target.disable();
apc_target_enabled= false;
end_read_record(&info); end_read_record(&info);
delete select; delete select;
thd_proc_info(thd, "end"); thd_proc_info(thd, "end");
...@@ -1035,8 +1030,6 @@ int mysql_update(THD *thd, ...@@ -1035,8 +1030,6 @@ int mysql_update(THD *thd,
DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0); DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0);
err: err:
if (apc_target_enabled)
thd->apc_target.disable();
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
...@@ -1045,7 +1038,6 @@ err: ...@@ -1045,7 +1038,6 @@ err:
DBUG_RETURN(1); DBUG_RETURN(1);
exit_without_my_ok: exit_without_my_ok:
DBUG_ASSERT(!apc_target_enabled);
query_plan.save_explain_data(thd->lex->explain); query_plan.save_explain_data(thd->lex->explain);
int err2= thd->lex->explain->send_explain(thd); int err2= thd->lex->explain->send_explain(thd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment