summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Petrunya <psergey@askmonty.org>2013-10-14 20:09:33 +0400
committerSergey Petrunya <psergey@askmonty.org>2013-10-14 20:09:33 +0400
commit105e3ae6c93f57498fa6c504dfbb92203b0d1056 (patch)
tree8148f8bc8bbd717f5b4540e0ea8a7673a490fc00
parentf67f8fd00fa6cf4bb38b10094060e6842a7d8daa (diff)
downloadmariadb-git-105e3ae6c93f57498fa6c504dfbb92203b0d1056.tar.gz
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()).
-rw-r--r--mysql-test/r/show_explain.result11
-rw-r--r--mysql-test/t/show_explain.test4
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_delete.cc11
-rw-r--r--sql/sql_explain.cc34
-rw-r--r--sql/sql_explain.h24
-rw-r--r--sql/sql_insert.cc5
-rw-r--r--sql/sql_lex.cc8
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_select.cc10
-rw-r--r--sql/sql_update.cc8
11 files changed, 76 insertions, 45 deletions
diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result
index c124048aca5..7e0ac0b277c 100644
--- a/mysql-test/r/show_explain.result
+++ b/mysql-test/r/show_explain.result
@@ -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;
diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test
index 91e3be34408..6735a0e851e 100644
--- a/mysql-test/t/show_explain.test
+++ b/mysql-test/t/show_explain.test
@@ -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;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ffc77224c12..5926f56d644 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -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)
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 7f58526d174..fae44a72205 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -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
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index f8d544a52e9..b9f75d3a97e 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -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;
}
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 2eb9e528a67..12621b88d23 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -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
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index cbc44700b17..24b43442e2a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -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);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index bd31200e749..09cb8f06afc 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index c5b9c1eada2..0d22e815f5f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a51fcd07b58..f7e3dcad7ed 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index a5f81a9e89e..6a58b4e8029 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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);