summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2015-03-24 16:26:42 +0300
committerSergei Petrunia <psergey@askmonty.org>2015-03-24 16:26:42 +0300
commit4106dfe89b772a78dfc39b79082dd08158cf91ad (patch)
treee767156672e96c780529bca99e6341da282e6d84 /sql
parentec68494beb151bc01ff6885476d2d4aeab3fe345 (diff)
parent77e16ce7d65793451c640014b342d23a28fc1060 (diff)
downloadmariadb-git-4106dfe89b772a78dfc39b79082dd08158cf91ad.tar.gz
Merge branch 'bb-10.1-explain-analyze' into 10.1
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/handler.cc63
-rw-r--r--sql/handler.h5
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/mysqld.h3
-rw-r--r--sql/sql_analyze_stmt.h50
-rw-r--r--sql/sql_class.h22
-rw-r--r--sql/sql_explain.cc13
-rw-r--r--sql/sql_explain.h85
-rw-r--r--sql/sql_select.cc4
-rw-r--r--sql/sql_select.h5
11 files changed, 216 insertions, 39 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 9a2ab3c72c8..8c426d010f8 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -105,6 +105,7 @@ SET (SQL_SOURCE
# added in MariaDB:
sql_explain.h sql_explain.cc
+ sql_analyze_stmt.h
sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc
create_options.cc multi_range_read.cc
opt_index_cond_pushdown.cc opt_subselect.cc
diff --git a/sql/handler.cc b/sql/handler.cc
index 2df1476f0e4..b47c9153e7c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -43,6 +43,8 @@
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_audit.h"
+#include "sql_analyze_stmt.h" // tracker in TABLE_IO_WAIT
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
@@ -54,6 +56,17 @@
#include "wsrep_mysqld.h"
#include "wsrep.h"
+#define TABLE_IO_WAIT(TRACKER, PSI, OP, INDEX, FLAGS, PAYLOAD) \
+ { \
+ if (unlikely(tracker)) \
+ tracker->start_tracking(); \
+ \
+ MYSQL_TABLE_IO_WAIT(PSI, OP, INDEX, FLAGS, PAYLOAD); \
+ \
+ if (unlikely(tracker)) \
+ tracker->stop_tracking(); \
+ }
+
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
@@ -2566,12 +2579,38 @@ int handler::ha_close(void)
status_var_add(table->in_use->status_var.rows_tmp_read, rows_tmp_read);
PSI_CALL_close_table(m_psi);
m_psi= NULL; /* instrumentation handle, invalid after close_table() */
+
+ /* Detach from ANALYZE tracker */
+ tracker= NULL;
DBUG_ASSERT(m_lock_type == F_UNLCK);
DBUG_ASSERT(inited == NONE);
DBUG_RETURN(close());
}
+inline int handler::ha_write_tmp_row(uchar *buf)
+{
+ int error;
+ MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
+ increment_statistics(&SSV::ha_tmp_write_count);
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
+ { error= write_row(buf); })
+ MYSQL_INSERT_ROW_DONE(error);
+ return error;
+}
+
+inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data)
+{
+ int error;
+ MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
+ increment_statistics(&SSV::ha_tmp_update_count);
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
+ { error= update_row(old_data, new_data);})
+ MYSQL_UPDATE_ROW_DONE(error);
+ return error;
+}
+
+
int handler::ha_rnd_next(uchar *buf)
{
int result;
@@ -2580,7 +2619,7 @@ int handler::ha_rnd_next(uchar *buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited == RND);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
{ result= rnd_next(buf); })
if (!result)
{
@@ -2605,7 +2644,7 @@ int handler::ha_rnd_pos(uchar *buf, uchar *pos)
/* TODO: Find out how to solve ha_rnd_pos when finding duplicate update. */
/* DBUG_ASSERT(inited == RND); */
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0,
{ result= rnd_pos(buf, pos); })
increment_statistics(&SSV::ha_read_rnd_count);
if (!result)
@@ -2624,7 +2663,7 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key,
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ result= index_read_map(buf, key, keypart_map, find_flag); })
increment_statistics(&SSV::ha_read_key_count);
if (!result)
@@ -2648,7 +2687,7 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key,
DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE ||
m_lock_type != F_UNLCK);
DBUG_ASSERT(end_range == NULL);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, index, 0,
{ result= index_read_idx_map(buf, index, key, keypart_map, find_flag); })
increment_statistics(&SSV::ha_read_key_count);
if (!result)
@@ -2668,7 +2707,7 @@ int handler::ha_index_next(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ result= index_next(buf); })
increment_statistics(&SSV::ha_read_next_count);
if (!result)
@@ -2685,7 +2724,7 @@ int handler::ha_index_prev(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ result= index_prev(buf); })
increment_statistics(&SSV::ha_read_prev_count);
if (!result)
@@ -2701,7 +2740,7 @@ int handler::ha_index_first(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ result= index_first(buf); })
increment_statistics(&SSV::ha_read_first_count);
if (!result)
@@ -2717,7 +2756,7 @@ int handler::ha_index_last(uchar * buf)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ result= index_last(buf); })
increment_statistics(&SSV::ha_read_last_count);
if (!result)
@@ -2733,7 +2772,7 @@ int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen)
m_lock_type != F_UNLCK);
DBUG_ASSERT(inited==INDEX);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_FETCH_ROW, active_index, 0,
{ result= index_next_same(buf, key, keylen); })
increment_statistics(&SSV::ha_read_next_count);
if (!result)
@@ -5857,7 +5896,7 @@ int handler::ha_write_row(uchar *buf)
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
@@ -5890,7 +5929,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
{ error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
@@ -5918,7 +5957,7 @@ int handler::ha_delete_row(const uchar *buf)
mark_trx_read_write();
increment_statistics(&SSV::ha_delete_count);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
{ error= delete_row(buf);})
MYSQL_DELETE_ROW_DONE(error);
if (unlikely(error))
diff --git a/sql/handler.h b/sql/handler.h
index 5ab67c045ec..d48be007522 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1571,6 +1571,7 @@ typedef struct {
#define UNDEF_NODEGROUP 65535
class Item;
+class Exec_time_tracker;
struct st_table_log_memory_entry;
class partition_info;
@@ -2594,6 +2595,9 @@ public:
ulonglong rows_changed;
/* One bigger than needed to avoid to test if key == MAX_KEY */
ulonglong index_rows_read[MAX_KEY+1];
+
+ /* ANALYZE time tracker, if present */
+ Exec_time_tracker *tracker;
Item *pushed_idx_cond;
uint pushed_idx_cond_keyno; /* The index which the above condition is for */
@@ -2648,6 +2652,7 @@ public:
ft_handler(0), inited(NONE),
implicit_emptied(0),
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
+ tracker(NULL),
pushed_idx_cond(NULL),
pushed_idx_cond_keyno(MAX_KEY),
auto_inc_intervals_count(0),
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d050c756dd1..14d904bbe74 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -314,6 +314,9 @@ arg_cmp_func Arg_comparator::comparator_matrix[6][2] =
{&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal},
{&Arg_comparator::compare_datetime, &Arg_comparator::compare_e_datetime}};
+/* Timer info to be used by the SQL layer */
+MY_TIMER_INFO sys_timer_info;
+
/* static variables */
#ifdef HAVE_PSI_INTERFACE
@@ -5461,6 +5464,7 @@ int mysqld_main(int argc, char **argv)
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
pfs_param.m_pfs_instrument= const_cast<char*>("");
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
+ my_timer_init(&sys_timer_info);
int ho_error __attribute__((unused))= handle_early_options();
diff --git a/sql/mysqld.h b/sql/mysqld.h
index b0b31856e52..00763d56d77 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -26,6 +26,7 @@
#include "sql_cmd.h"
#include <my_rnd.h>
#include "my_pthread.h"
+#include "my_rdtsc.h"
class THD;
struct handlerton;
@@ -60,6 +61,8 @@ typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
#define OPT_SESSION SHOW_OPT_SESSION
#define OPT_GLOBAL SHOW_OPT_GLOBAL
+extern MY_TIMER_INFO sys_timer_info;
+
/*
Values for --slave-parallel-mode
Must match order in slave_parallel_mode_typelib in sys_vars.cc.
diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h
new file mode 100644
index 00000000000..f83ae1a57a6
--- /dev/null
+++ b/sql/sql_analyze_stmt.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (c) 2015 MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/*
+ A class for tracking time it takes to do a certain action
+*/
+class Exec_time_tracker
+{
+ ulonglong count;
+ ulonglong cycles;
+ ulonglong last_start;
+public:
+ Exec_time_tracker() : count(0), cycles(0) {}
+
+ // interface for collecting time
+ void start_tracking()
+ {
+ last_start= my_timer_cycles();
+ }
+
+ void stop_tracking()
+ {
+ ulonglong last_end= my_timer_cycles();
+ count++;
+ cycles += last_end - last_start;
+ }
+
+ // interface for getting the time
+ ulonglong get_loops() { return count; }
+ double get_time_ms()
+ {
+ // convert 'cycles' to milliseconds.
+ return 1000 * ((double)cycles) / sys_timer_info.cycles.frequency;
+ }
+};
+
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d391d25c362..1273b28cd0b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5271,28 +5271,6 @@ inline int handler::ha_read_first_row(uchar *buf, uint primary_key)
return error;
}
-inline int handler::ha_write_tmp_row(uchar *buf)
-{
- int error;
- MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
- increment_statistics(&SSV::ha_tmp_write_count);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
- { error= write_row(buf); })
- MYSQL_INSERT_ROW_DONE(error);
- return error;
-}
-
-inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data)
-{
- int error;
- MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
- increment_statistics(&SSV::ha_tmp_update_count);
- MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0,
- { error= update_row(old_data, new_data);})
- MYSQL_UPDATE_ROW_DONE(error);
- return error;
-}
-
extern pthread_attr_t *get_connection_attrib(void);
/**
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index aa16a744e83..9d82f4fe19f 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -732,7 +732,12 @@ void Explain_select::print_explain_json(Explain_query *query,
*/
writer->add_member("query_block").start_object();
writer->add_member("select_id").add_ll(select_id);
-
+
+ if (is_analyze && time_tracker.get_loops())
+ {
+ writer->add_member("r_loops").add_ll(time_tracker.get_loops());
+ writer->add_member("r_total_time_ms").add_double(time_tracker.get_time_ms());
+ }
if (exec_const_cond)
{
writer->add_member("const_condition");
@@ -1289,6 +1294,12 @@ void Explain_table_access::print_explain_json(Explain_query *query,
}
else
writer->add_null();
+
+ if (op_tracker.get_loops())
+ {
+ writer->add_member("r_total_time_ms").
+ add_double(op_tracker.get_time_ms());
+ }
}
/* `filtered` */
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 970edf7800d..50b351cf619 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -14,6 +14,44 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "sql_analyze_stmt.h"
+
+/*
+
+== EXPLAIN/ANALYZE architecture ==
+
+=== [SHOW] EXPLAIN data ===
+Query optimization produces two data structures:
+1. execution data structures themselves (eg. JOINs, JOIN_TAB, etc, etc)
+2. Explain data structures.
+
+#2 are self contained set of data structures that has sufficient info to
+produce output of SHOW EXPLAIN, EXPLAIN [FORMAT=JSON], or
+ANALYZE [FORMAT=JSON], without accessing the execution data structures.
+
+(the only exception is that Explain data structures keep Item* pointers,
+and we require that one might call item->print(QT_EXPLAIN) when printing
+FORMAT=JSON output)
+
+=== ANALYZE data ===
+EXPLAIN data structures have embedded ANALYZE data structures. These are
+objects that are used to track how the parts of query plan were executed:
+how many times each part of query plan was invoked, how many rows were
+read/returned, etc.
+
+Each execution data structure keeps a direct pointer to its ANALYZE data
+structure. It is needed so that execution code can quickly increment the
+counters.
+
+(note that this increases the set of data that is frequently accessed
+during the execution. What is the impact of this?)
+
+Since ANALYZE/EXPLAIN data structures are separated from execution data
+structures, it is easy to have them survive until the end of the query,
+where we can return ANALYZE [FORMAT=JSON] output to the user, or print
+it into the slow query log.
+
+*/
class String_list: public List<char>
{
@@ -21,12 +59,16 @@ public:
bool append_str(MEM_ROOT *mem_root, const char *str);
};
+class Json_writer;
/*
A class for collecting read statistics.
The idea is that we run several scans. Each scans gets rows, and then filters
some of them out. We count scans, rows, and rows left after filtering.
+
+ (note: at the moment, the class is not actually tied to a physical table.
+ It can be used to track reading from files, buffers, etc).
*/
class Table_access_tracker
@@ -39,7 +81,6 @@ public:
ha_rows r_scans; /* How many scans were ran on this join_tab */
ha_rows r_rows; /* How many rows we've got after that */
-// ha_rows r_rows_after_table_cond; /* Rows after applying the table condition */
ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */
bool has_scans() { return (r_scans != 0); }
@@ -65,6 +106,39 @@ public:
inline void on_record_after_where() { r_rows_after_where++; }
};
+#if 0
+/*
+ A class to track operations (currently, row reads) on a PSI_table.
+*/
+class Table_op_tracker
+{
+ PSI_table *psi_table;
+
+ /* Table counter values at start. Sum is in picoseconds */
+ ulonglong start_sum;
+ ulonglong start_count;
+
+ /* Table counter values at end */
+ ulonglong end_sum;
+ ulonglong end_count;
+public:
+ void start_tracking(TABLE *table);
+ // At the moment, print_json will call end_tracking.
+ void end_tracking();
+
+ // this may print nothing if the table was not tracked.
+ void print_json(Json_writer *writer);
+};
+#endif
+
+#define ANALYZE_START_TRACKING(tracker) \
+ if (tracker) \
+ { tracker->start_tracking(); }
+
+#define ANALYZE_STOP_TRACKING(tracker) \
+ if (tracker) \
+ { tracker->stop_tracking(); }
+
/**************************************************************************************
@@ -82,8 +156,6 @@ const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
class Explain_query;
-class Json_writer;
-
/*
A node can be either a SELECT, or a UNION.
*/
@@ -231,6 +303,9 @@ public:
/* Global join attributes. In tabular form, they are printed on the first row */
bool using_temporary;
bool using_filesort;
+
+ /* ANALYZE members */
+ Exec_time_tracker time_tracker;
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
@@ -639,7 +714,7 @@ public:
// Valid if ET_USING tag is present
Explain_quick_select *quick_info;
- /* Non-NULL values means this tab uses "range checked for each record" */
+ /* Non-NULL value means this tab uses "range checked for each record" */
Explain_range_checked_fer *range_checked_fer;
bool full_scan_on_null_key;
@@ -666,6 +741,7 @@ public:
/* Tracker for reading the table */
Table_access_tracker tracker;
+ Exec_time_tracker op_tracker;
Table_access_tracker jbuf_tracker;
int print_explain(select_result_sink *output, uint8 explain_flags,
@@ -735,6 +811,7 @@ public:
/* ANALYZE members and methods */
Table_access_tracker tracker;
+ //psergey-todo: io-tracker here.
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 15290b218ac..5c3e1167894 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2390,7 +2390,9 @@ void JOIN::exec()
select_lex->select_number))
dbug_serve_apcs(thd, 1);
);
+ ANALYZE_START_TRACKING(tracker);
exec_inner();
+ ANALYZE_STOP_TRACKING(tracker);
DBUG_EXECUTE_IF("show_explain_probe_join_exec_end",
if (dbug_user_var_equals_int(thd,
@@ -23404,6 +23406,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
tab->tracker= &eta->tracker;
tab->jbuf_tracker= &eta->jbuf_tracker;
+ tab->table->file->tracker= &eta->op_tracker;
/* id and select_type are kept in Explain_select */
/* table */
@@ -23842,6 +23845,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
Explain_select *xpl_sel;
explain_node= xpl_sel= new (output->mem_root) Explain_select(output->mem_root);
table_map used_tables=0;
+ tracker= &xpl_sel->time_tracker;
join->select_lex->set_explain_type(true);
xpl_sel->select_id= join->select_lex->select_number;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index dcfb6778ccc..0557e328ea0 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -252,6 +252,7 @@ typedef struct st_join_table {
enum explain_extra_tag info;
Table_access_tracker *tracker;
+
Table_access_tracker *jbuf_tracker;
/*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
@@ -1260,6 +1261,8 @@ public:
OPTIMIZATION_DONE=2};
bool optimized; ///< flag to avoid double optimization in EXPLAIN
bool initialized; ///< flag to avoid double init_execution calls
+
+ Exec_time_tracker *tracker;
enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE, QEP_DELETED} have_query_plan;
@@ -1354,6 +1357,8 @@ public:
no_rows_in_result_called= 0;
positions= best_positions= 0;
+ tracker= NULL;
+
all_fields= fields_arg;
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
fields_list= fields_arg;