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';
set @foo= (select max(a) from t0 where sin(a) >0);
show explain for $thr2;
ERROR HY000: Target is not running an EXPLAINable command
kill query $thr2;
ERROR 70100: Query execution was interrupted
set debug_dbug=@old_debug;
#
# Attempt SHOW EXPLAIN for an UPDATE
......@@ -405,13 +407,8 @@ set debug_dbug='+d,show_explain_probe_join_exec_end';
SELECT * FROM v1, t2;
show explain for $thr2;
ERROR HY000: Target is not running an EXPLAINable command
a b
8 4
8 5
8 6
8 7
8 8
8 9
kill query $thr2;
ERROR 70100: Query execution was interrupted
set debug_dbug=@old_debug;
DROP VIEW v1;
DROP TABLE t2, t3;
......
......@@ -224,7 +224,9 @@ connection default;
--source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
evalp kill query $thr2;
connection con1;
--error ER_QUERY_INTERRUPTED
reap;
set debug_dbug=@old_debug;
......@@ -399,7 +401,9 @@ connection default;
--source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE
evalp show explain for $thr2;
evalp kill query $thr2;
connection con1;
--error ER_QUERY_INTERRUPTED
reap;
set debug_dbug=@old_debug;
DROP VIEW v1;
......
......@@ -3037,7 +3037,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
else if (! thd->in_sub_stmt)
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);
if (m_lex->query_tables_own_last)
......
......@@ -66,8 +66,8 @@ void Delete_plan::save_explain_data(Explain_query *query)
explain->deleting_all_rows= false;
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)
{
Explain_update* explain= new Explain_update;
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,
goto exit_without_my_ok;
query_plan.save_explain_data(thd->lex->explain);
thd->apc_target.enable();
DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start",
dbug_serve_apcs(thd, 1););
......@@ -486,7 +485,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
thd->apc_target.disable();
DBUG_RETURN(TRUE);
}
thd->examined_row_count+= examined_rows;
......@@ -505,7 +503,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
delete select;
free_underlaid_joins(thd, select_lex);
thd->apc_target.disable();
DBUG_RETURN(TRUE);
}
if (query_plan.index == MAX_KEY || (select && select->quick))
......@@ -514,7 +511,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
delete select;
free_underlaid_joins(thd, select_lex);
thd->apc_target.disable();
DBUG_RETURN(TRUE);
}
}
......@@ -624,7 +620,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
thd->apc_target.disable();
cleanup:
/*
Invalidate the table in the query cache if something changed. This must
......
......@@ -22,7 +22,8 @@
#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;
}
......@@ -30,6 +31,9 @@ Explain_query::Explain_query() : upd_del_plan(NULL), insert_plan(NULL)
Explain_query::~Explain_query()
{
if (apc_enabled)
thd->apc_target.disable();
delete upd_del_plan;
delete insert_plan;
uint i;
......@@ -62,11 +66,12 @@ Explain_select *Explain_query::get_select(uint select_id)
void Explain_query::add_node(Explain_node *node)
{
uint select_id;
operations++;
if (node->get_type() == Explain_node::EXPLAIN_UNION)
{
Explain_union *u= (Explain_union*)node;
uint select_id= u->get_select_id();
select_id= u->get_select_id();
if (unions.elements() <= select_id)
unions.resize(max(select_id+1, unions.elements()*2), NULL);
......@@ -85,7 +90,7 @@ void Explain_query::add_node(Explain_node *node)
}
else
{
uint select_id= sel->select_id;
select_id= sel->select_id;
Explain_select *old_node;
if (selects.elements() <= select_id)
......@@ -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.
*/
......@@ -915,7 +941,7 @@ void delete_explain_query(LEX *lex)
void create_explain_query(LEX *lex, MEM_ROOT *mem_root)
{
DBUG_ASSERT(!lex->explain);
lex->explain= new Explain_query;
lex->explain= new Explain_query(lex->thd);
DBUG_ASSERT(mem_root == current_thd->mem_root);
lex->explain->mem_root= mem_root;
}
......
......@@ -221,10 +221,13 @@ class Explain_insert;
class Explain_query : public Sql_alloc
{
public:
Explain_query();
Explain_query(THD *thd);
~Explain_query();
/* Add a new 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 */
Explain_node *get_node(uint select_id);
......@@ -233,13 +236,7 @@ public:
Explain_select *get_select(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 */
int print_explain(select_result_sink *output, uint8 explain_flags);
......@@ -251,11 +248,22 @@ public:
/* If true, at least part of EXPLAIN can be printed */
bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; }
void query_plan_ready();
MEM_ROOT *mem_root;
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_select*> selects;
THD *thd; // for APC start/stop
bool apc_enabled;
/*
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
......
......@@ -461,7 +461,8 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
thd->variables.max_insert_delayed_threads == 0 ||
thd->locked_tables_mode > LTM_LOCK_TABLES ||
thd->lex->uses_stored_routines())
thd->lex->uses_stored_routines() /*||
thd->lex->describe*/)
{
*lock_type= TL_WRITE;
return;
......@@ -649,7 +650,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
Explain_insert* explain= new Explain_insert;
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 */
bool skip= test(table_list->view);
......
......@@ -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())
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
output->add_node(eu);
eu->fake_select_type= "UNION RESULT";
eu->using_filesort= test(global_parameters->order_list.first);
if (eu->get_select_id() == 1)
output->query_plan_ready();
return 0;
}
......
......@@ -1031,6 +1031,10 @@ public:
void clear_index_hints(void) { index_hints= NULL; }
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);
/* Set the EXPLAIN type for this subquery. */
void set_explain_type(bool on_the_fly);
......
......@@ -2298,8 +2298,6 @@ JOIN::save_join_tab()
void join_save_qpf(JOIN *join)
{
THD *thd= join->thd;
//TODO: why not call st_select_lex::save_qpf here?
if (join->select_lex->select_number != UINT_MAX &&
join->select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
join->have_query_plan != JOIN::QEP_NOT_PRESENT_YET &&
......@@ -2315,7 +2313,7 @@ void join_save_qpf(JOIN *join)
/* It's a degenerate join */
message= join->zero_result_cause ? join->zero_result_cause : "No tables used";
}
join->save_explain_data(thd->lex->explain,
join->need_tmp,
!join->skip_sort_order && !join->no_order &&
......@@ -2328,7 +2326,6 @@ void join_save_qpf(JOIN *join)
void JOIN::exec()
{
thd->apc_target.enable();
DBUG_EXECUTE_IF("show_explain_probe_join_exec_start",
if (dbug_user_var_equals_int(thd,
"show_explain_probe_select_id",
......@@ -2368,7 +2365,6 @@ void JOIN::exec()
select_lex->select_number))
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,
}
}
if (!error && select_lex->is_top_level_node())
output->query_plan_ready();
DBUG_RETURN(error);
}
......
......@@ -279,7 +279,6 @@ int mysql_update(THD *thd,
Update_plan query_plan(thd->mem_root);
query_plan.index= MAX_KEY;
query_plan.using_filesort= FALSE;
bool apc_target_enabled= false; // means was enabled *by code this function*
DBUG_ENTER("mysql_update");
if (open_tables(thd, &table_list, &table_count, 0))
......@@ -518,8 +517,6 @@ int mysql_update(THD *thd,
goto exit_without_my_ok;
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_serve_apcs(thd, 1););
......@@ -960,8 +957,6 @@ int mysql_update(THD *thd,
if (!transactional_table && updated > 0)
thd->transaction.stmt.modified_non_trans_table= TRUE;
thd->apc_target.disable();
apc_target_enabled= false;
end_read_record(&info);
delete select;
thd_proc_info(thd, "end");
......@@ -1035,8 +1030,6 @@ int mysql_update(THD *thd,
DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0);
err:
if (apc_target_enabled)
thd->apc_target.disable();
delete select;
free_underlaid_joins(thd, select_lex);
......@@ -1045,7 +1038,6 @@ err:
DBUG_RETURN(1);
exit_without_my_ok:
DBUG_ASSERT(!apc_target_enabled);
query_plan.save_explain_data(thd->lex->explain);
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