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()).
This commit is contained in:
parent
f67f8fd00f
commit
105e3ae6c9
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user