diff options
author | Sergey Petrunya <psergey@askmonty.org> | 2013-10-14 20:09:33 +0400 |
---|---|---|
committer | Sergey Petrunya <psergey@askmonty.org> | 2013-10-14 20:09:33 +0400 |
commit | 105e3ae6c93f57498fa6c504dfbb92203b0d1056 (patch) | |
tree | 8148f8bc8bbd717f5b4540e0ea8a7673a490fc00 | |
parent | f67f8fd00fa6cf4bb38b10094060e6842a7d8daa (diff) | |
download | mariadb-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.result | 11 | ||||
-rw-r--r-- | mysql-test/t/show_explain.test | 4 | ||||
-rw-r--r-- | sql/sp_head.cc | 2 | ||||
-rw-r--r-- | sql/sql_delete.cc | 11 | ||||
-rw-r--r-- | sql/sql_explain.cc | 34 | ||||
-rw-r--r-- | sql/sql_explain.h | 24 | ||||
-rw-r--r-- | sql/sql_insert.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.cc | 8 | ||||
-rw-r--r-- | sql/sql_lex.h | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 10 | ||||
-rw-r--r-- | sql/sql_update.cc | 8 |
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); |