Commit 3841e921 authored by Sergei Petrunia's avatar Sergei Petrunia

Merge branch 'bb-10.1-explain-analyze' into 10.1

parents 34fcc28e f42064a1
......@@ -7,12 +7,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 30,
"attached_condition": "(t0.a < 3)"
......@@ -32,12 +35,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 0,
"attached_condition": "((t0.a > 9) and (t0.a is not null))"
......@@ -69,12 +75,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t0",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100,
"attached_condition": "(t0.a is not null)"
......@@ -90,6 +99,7 @@ EXPLAIN
"r_loops": 10,
"rows": 1,
"r_rows": 1,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 40,
"attached_condition": "(t1.b < 4)"
......@@ -107,12 +117,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 20,
"attached_condition": "(tbl1.b < 20)"
......@@ -124,6 +137,7 @@ EXPLAIN
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 60,
"attached_condition": "(tbl2.b < 60)"
......@@ -140,12 +154,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "tbl1",
"access_type": "ALL",
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 20,
"attached_condition": "(tbl1.b < 20)"
......@@ -157,6 +174,7 @@ EXPLAIN
"r_loops": 1,
"rows": 100,
"r_rows": 100,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 60,
"attached_condition": "(tbl2.b < 60)"
......@@ -182,12 +200,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100,
"attached_condition": "(t1.a is not null)"
......@@ -203,6 +224,7 @@ EXPLAIN
"r_loops": 10,
"rows": 2,
"r_rows": 0.2,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 100,
"using_index": true
......@@ -226,12 +248,15 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 10,
"r_rows": 10,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 50,
"attached_condition": "(test.t1.a < 5)"
......
......@@ -9,28 +9,34 @@ create table t0 (a int);
INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
--echo # r_filtered=30%, because 3 rows match: 0,1,2
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json select * from t0 where a<3;
create table t1 (a int, b int, c int, key(a));
insert into t1 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B;
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json
select * from t0, t1 where t1.a=t0.a and t0.a > 9;
analyze
select * from t0, t1 where t1.a=t0.a and t1.b<4;
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json
select * from t0, t1 where t1.a=t0.a and t1.b<4;
analyze
select * from t1 tbl1, t1 tbl2 where tbl1.b<2 and tbl2.b>5;
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60;
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json
select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60 and tbl1.c > tbl2.c;
......@@ -47,6 +53,7 @@ insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (a int, key(a));
insert into t2 values (0),(1);
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json select * from t1 straight_join t2 force index(a) where t2.a=t1.a;
drop table t1,t2;
......@@ -62,6 +69,7 @@ select database();
connect (con1,localhost,root,,*NO-ONE*);
connection con1;
select database();
--replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/
analyze format=json select * from test.t1 where t1.a<5;
disconnect con1;
connection default;
......
......@@ -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
......
......@@ -2566,12 +2566,16 @@ 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());
}
int handler::ha_rnd_next(uchar *buf)
{
int result;
......@@ -2580,7 +2584,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 +2609,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 +2628,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 +2652,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 +2672,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 +2689,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 +2705,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 +2721,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 +2737,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)
......@@ -5837,6 +5841,7 @@ int handler::ha_reset()
/* reset the bitmaps to point to defaults */
table->default_column_bitmaps();
pushed_cond= NULL;
tracker= NULL;
/* Reset information about pushed engine conditions */
cancel_pushed_idx_cond();
/* Reset information about pushed index conditions */
......@@ -5857,7 +5862,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 +5895,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 +5923,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))
......
......@@ -34,6 +34,8 @@
#include "sql_array.h" /* Dynamic_array<> */
#include "mdl.h"
#include "sql_analyze_stmt.h" // for Exec_time_tracker
#include <my_compare.h>
#include <ft_global.h>
#include <keycache.h>
......@@ -2594,6 +2596,9 @@ class handler :public Sql_alloc
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 +2653,7 @@ class handler :public Sql_alloc
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),
......@@ -4201,6 +4207,18 @@ inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
}
#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(); \
}
void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag);
void print_keydup_error(TABLE *table, KEY *key, myf errflag);
#endif
......@@ -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();
......
......@@ -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.
......
/*
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;
}
};
......@@ -5276,8 +5276,8 @@ 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); })
TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
return error;
}
......@@ -5287,12 +5287,13 @@ 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);})
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;
}
extern pthread_attr_t *get_connection_attrib(void);
/**
......
......@@ -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` */
......
......@@ -14,6 +14,42 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
== 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 +57,16 @@ class String_list: public List<char>
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 +79,6 @@ class Table_access_tracker
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 +104,39 @@ class Table_access_tracker
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 +154,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 +301,9 @@ class Explain_select : public Explain_basic_join
/* 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 +712,7 @@ class Explain_table_access : public Sql_alloc
// 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 +739,7 @@ class Explain_table_access : public Sql_alloc
/* 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 +809,7 @@ class Explain_update : public Explain_node
/* 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);
......
......@@ -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;
......
......@@ -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 @@ class JOIN :public Sql_alloc
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 @@ class JOIN :public Sql_alloc
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;
......
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