Commit 9d2aa2b3 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-7811: EXPLAIN/ANALYZE FORMAT=JSON should show subquery cache

Fixes over the original patch:
- Fix variable/class/other names
- Fix the JSON output to be in line with the output of other JSON
  constructs we produce
parent c6aee27b
...@@ -59,27 +59,24 @@ ANALYZE ...@@ -59,27 +59,24 @@ ANALYZE
}, },
"subqueries": [ "subqueries": [
{ {
"query_block": { "expression_cache": {
"select_id": 2, "r_loops": 10,
"r_loops": 4, "r_hit_ratio": 60,
"r_total_time_ms": "REPLACED", "query_block": {
"expression_cache": { "select_id": 2,
"state": "ENABLED",
"r_hit": 6,
"r_miss": 4,
"r_loops": 10,
"r_hit_ratio": 60
},
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 4, "r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED", "r_total_time_ms": "REPLACED",
"filtered": 100, "table": {
"r_filtered": 18.75, "table_name": "t2",
"attached_condition": "(t1.b = t2.c)" "access_type": "ALL",
"r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 18.75,
"attached_condition": "(t1.b = t2.c)"
}
} }
} }
} }
...@@ -106,72 +103,66 @@ ANALYZE ...@@ -106,72 +103,66 @@ ANALYZE
}, },
"subqueries": [ "subqueries": [
{ {
"query_block": { "expression_cache": {
"union_result": { "r_loops": 10,
"table_name": "<union3,4>", "r_hit_ratio": 60,
"access_type": "ALL", "query_block": {
"r_loops": 4, "union_result": {
"r_rows": 1, "table_name": "<union3,4>",
"expression_cache": { "access_type": "ALL",
"state": "ENABLED", "r_loops": 4,
"r_hit": 6, "r_rows": 1,
"r_miss": 4, "query_specifications": [
"r_loops": 10, {
"r_hit_ratio": 60 "query_block": {
}, "select_id": 3,
"query_specifications": [
{
"query_block": {
"select_id": 3,
"r_loops": 4,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 4, "r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED", "r_total_time_ms": "REPLACED",
"filtered": 100, "table": {
"r_filtered": 18.75, "table_name": "t2",
"attached_condition": "(t1.b = t2.c)" "access_type": "ALL",
"r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 18.75,
"attached_condition": "(t1.b = t2.c)"
}
} }
} },
}, {
{ "query_block": {
"query_block": { "select_id": 4,
"select_id": 4, "table": {
"table": { "message": "No tables used"
"message": "No tables used" }
} }
} }
} ]
] }
} }
} }
}, },
{ {
"query_block": { "expression_cache": {
"select_id": 2, "r_loops": 10,
"r_loops": 4, "r_hit_ratio": 60,
"r_total_time_ms": "REPLACED", "query_block": {
"expression_cache": { "select_id": 2,
"state": "ENABLED",
"r_hit": 6,
"r_miss": 4,
"r_loops": 10,
"r_hit_ratio": 60
},
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 4, "r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED", "r_total_time_ms": "REPLACED",
"filtered": 100, "table": {
"r_filtered": 18.75, "table_name": "t2",
"attached_condition": "(t1.b = t2.c)" "access_type": "ALL",
"r_loops": 4,
"rows": 4,
"r_rows": 4,
"r_total_time_ms": "REPLACED",
"filtered": 100,
"r_filtered": 18.75,
"attached_condition": "(t1.b = t2.c)"
}
} }
} }
} }
...@@ -192,17 +183,17 @@ EXPLAIN ...@@ -192,17 +183,17 @@ EXPLAIN
}, },
"subqueries": [ "subqueries": [
{ {
"query_block": { "expression_cache": {
"select_id": 2, "state": "uninitialized",
"expression_cache": { "query_block": {
"state": "UNINITIALYZED" "select_id": 2,
}, "table": {
"table": { "table_name": "t2",
"table_name": "t2", "access_type": "ALL",
"access_type": "ALL", "rows": 4,
"rows": 4, "filtered": 100,
"filtered": 100, "attached_condition": "(t1.b = t2.c)"
"attached_condition": "(t1.b = t2.c)" }
} }
} }
} }
...@@ -223,50 +214,50 @@ EXPLAIN ...@@ -223,50 +214,50 @@ EXPLAIN
}, },
"subqueries": [ "subqueries": [
{ {
"query_block": { "expression_cache": {
"union_result": { "state": "uninitialized",
"table_name": "<union3,4>", "query_block": {
"access_type": "ALL", "union_result": {
"expression_cache": { "table_name": "<union3,4>",
"state": "UNINITIALYZED" "access_type": "ALL",
}, "query_specifications": [
"query_specifications": [ {
{ "query_block": {
"query_block": { "select_id": 3,
"select_id": 3, "table": {
"table": { "table_name": "t2",
"table_name": "t2", "access_type": "ALL",
"access_type": "ALL", "rows": 4,
"rows": 4, "filtered": 100,
"filtered": 100, "attached_condition": "(t1.b = t2.c)"
"attached_condition": "(t1.b = t2.c)" }
} }
} },
}, {
{ "query_block": {
"query_block": { "select_id": 4,
"select_id": 4, "table": {
"table": { "message": "No tables used"
"message": "No tables used" }
} }
} }
} ]
] }
} }
} }
}, },
{ {
"query_block": { "expression_cache": {
"select_id": 2, "state": "uninitialized",
"expression_cache": { "query_block": {
"state": "UNINITIALYZED" "select_id": 2,
}, "table": {
"table": { "table_name": "t2",
"table_name": "t2", "access_type": "ALL",
"access_type": "ALL", "rows": 4,
"rows": 4, "filtered": 100,
"filtered": 100, "attached_condition": "(t1.b = t2.c)"
"attached_condition": "(t1.b = t2.c)" }
} }
} }
} }
......
...@@ -7554,15 +7554,15 @@ bool Item_cache_wrapper::set_cache(THD *thd) ...@@ -7554,15 +7554,15 @@ bool Item_cache_wrapper::set_cache(THD *thd)
DBUG_RETURN(expr_cache == NULL); DBUG_RETURN(expr_cache == NULL);
} }
Expression_cache_stat* Item_cache_wrapper::set_stat(MEM_ROOT *mem_root) Expression_cache_tracker* Item_cache_wrapper::init_tracker(MEM_ROOT *mem_root)
{ {
if (expr_cache) if (expr_cache)
{ {
Expression_cache_stat* stat= Expression_cache_tracker* tracker=
new(mem_root) Expression_cache_stat(expr_cache); new(mem_root) Expression_cache_tracker(expr_cache);
if (stat) if (tracker)
((Expression_cache_tmptable *)expr_cache)->set_stat(stat); ((Expression_cache_tmptable *)expr_cache)->set_tracker(tracker);
return stat; return tracker;
} }
return NULL; return NULL;
} }
......
...@@ -3804,7 +3804,7 @@ public: ...@@ -3804,7 +3804,7 @@ public:
class Item_cache; class Item_cache;
class Expression_cache; class Expression_cache;
class Expression_cache_stat; class Expression_cache_tracker;
/** /**
The objects of this class can store its values in an expression cache. The objects of this class can store its values in an expression cache.
...@@ -3839,7 +3839,7 @@ public: ...@@ -3839,7 +3839,7 @@ public:
enum Type real_type() const { return orig_item->type(); } enum Type real_type() const { return orig_item->type(); }
bool set_cache(THD *thd); bool set_cache(THD *thd);
Expression_cache_stat* set_stat(MEM_ROOT *mem_root); Expression_cache_tracker* init_tracker(MEM_ROOT *mem_root);
bool fix_fields(THD *thd, Item **it); bool fix_fields(THD *thd, Item **it);
void cleanup(); void cleanup();
......
...@@ -1202,7 +1202,7 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(uchar *thd_arg) ...@@ -1202,7 +1202,7 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(uchar *thd_arg)
if (expr_cache_is_needed(thd) && if (expr_cache_is_needed(thd) &&
(expr_cache= set_expr_cache(thd))) (expr_cache= set_expr_cache(thd)))
{ {
set_expr_cache_stat(thd); init_expr_cache_tracker(thd);
DBUG_RETURN(expr_cache); DBUG_RETURN(expr_cache);
} }
DBUG_RETURN(this); DBUG_RETURN(this);
...@@ -1501,7 +1501,7 @@ Item* Item_exists_subselect::expr_cache_insert_transformer(uchar *thd_arg) ...@@ -1501,7 +1501,7 @@ Item* Item_exists_subselect::expr_cache_insert_transformer(uchar *thd_arg)
if (substype() == EXISTS_SUBS && expr_cache_is_needed(thd) && if (substype() == EXISTS_SUBS && expr_cache_is_needed(thd) &&
(expr_cache= set_expr_cache(thd))) (expr_cache= set_expr_cache(thd)))
{ {
set_expr_cache_stat(thd); init_expr_cache_tracker(thd);
DBUG_RETURN(expr_cache); DBUG_RETURN(expr_cache);
} }
DBUG_RETURN(this); DBUG_RETURN(this);
...@@ -6562,7 +6562,13 @@ void subselect_table_scan_engine::cleanup() ...@@ -6562,7 +6562,13 @@ void subselect_table_scan_engine::cleanup()
{ {
} }
void Item_subselect::set_expr_cache_stat(THD *thd)
/*
Create an execution tracker for the expression cache we're using for this
subselect; add the tracker to the query plan.
*/
void Item_subselect::init_expr_cache_tracker(THD *thd)
{ {
if(!expr_cache) if(!expr_cache)
return; return;
...@@ -6573,5 +6579,6 @@ void Item_subselect::set_expr_cache_stat(THD *thd) ...@@ -6573,5 +6579,6 @@ void Item_subselect::set_expr_cache_stat(THD *thd)
if (!node) if (!node)
return; return;
DBUG_ASSERT(expr_cache->type() == Item::EXPR_CACHE_ITEM); DBUG_ASSERT(expr_cache->type() == Item::EXPR_CACHE_ITEM);
node->cache_stat= ((Item_cache_wrapper *)expr_cache)->set_stat(qw->mem_root); node->cache_tracker= ((Item_cache_wrapper *)expr_cache)->init_tracker(qw->mem_root);
} }
...@@ -246,7 +246,7 @@ public: ...@@ -246,7 +246,7 @@ public:
return TRUE; return TRUE;
} }
void set_expr_cache_stat(THD *thd); void init_expr_cache_tracker(THD *thd);
friend class select_result_interceptor; friend class select_result_interceptor;
......
...@@ -521,6 +521,8 @@ void Explain_union::print_explain_json(Explain_query *query, ...@@ -521,6 +521,8 @@ void Explain_union::print_explain_json(Explain_query *query,
Json_writer_nesting_guard guard(writer); Json_writer_nesting_guard guard(writer);
char table_name_buffer[SAFE_NAME_LEN]; char table_name_buffer[SAFE_NAME_LEN];
bool started_object= print_explain_json_cache(writer, is_analyze);
writer->add_member("query_block").start_object(); writer->add_member("query_block").start_object();
writer->add_member("union_result").start_object(); writer->add_member("union_result").start_object();
// using_temporary_table // using_temporary_table
...@@ -544,7 +546,6 @@ void Explain_union::print_explain_json(Explain_query *query, ...@@ -544,7 +546,6 @@ void Explain_union::print_explain_json(Explain_query *query,
writer->add_null(); writer->add_null();
} }
print_explain_json_cache(writer, is_analyze);
writer->add_member("query_specifications").start_array(); writer->add_member("query_specifications").start_array();
for (int i= 0; i < (int) union_members.elements(); i++) for (int i= 0; i < (int) union_members.elements(); i++)
...@@ -562,6 +563,9 @@ void Explain_union::print_explain_json(Explain_query *query, ...@@ -562,6 +563,9 @@ void Explain_union::print_explain_json(Explain_query *query,
writer->end_object(); // union_result writer->end_object(); // union_result
writer->end_object(); // query_block writer->end_object(); // query_block
if (started_object)
writer->end_object();
} }
...@@ -642,27 +646,32 @@ void Explain_node::print_explain_json_for_children(Explain_query *query, ...@@ -642,27 +646,32 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
} }
void Explain_node::print_explain_json_cache(Json_writer *writer, bool Explain_node::print_explain_json_cache(Json_writer *writer,
bool is_analyze) bool is_analyze)
{ {
if (cache_stat) if (cache_tracker)
{
cache_tracker->fetch_current_stats();
writer->add_member("expression_cache").start_object();
if (cache_tracker->state != Expression_cache_tracker::OK)
{ {
cache_stat->flush_stat();
writer->add_member("expression_cache").start_object();
writer->add_member("state"). writer->add_member("state").
add_str(Expression_cache_stat::state_str[cache_stat->state]); add_str(Expression_cache_tracker::state_str[cache_tracker->state]);
if (is_analyze) }
if (is_analyze)
{
longlong cache_reads= cache_tracker->hit + cache_tracker->miss;
writer->add_member("r_loops").add_ll(cache_reads);
if (cache_reads != 0)
{ {
writer->add_member("r_hit").add_ll(cache_stat->hit); double hit_ratio= double(cache_tracker->hit) / cache_reads * 100.0;
writer->add_member("r_miss").add_ll(cache_stat->miss); writer->add_member("r_hit_ratio").add_double(hit_ratio);
writer->add_member("r_loops").add_ll(cache_stat->hit +
cache_stat->miss);
writer->add_member("r_hit_ratio").add_ll(((double)cache_stat->hit)/
((double)(cache_stat->hit +
cache_stat->miss)) * 100.0);
} }
writer->end_object();
} }
return true;
}
return false;
} }
...@@ -766,6 +775,8 @@ void Explain_select::print_explain_json(Explain_query *query, ...@@ -766,6 +775,8 @@ void Explain_select::print_explain_json(Explain_query *query,
Json_writer *writer, bool is_analyze) Json_writer *writer, bool is_analyze)
{ {
Json_writer_nesting_guard guard(writer); Json_writer_nesting_guard guard(writer);
bool started_cache= print_explain_json_cache(writer, is_analyze);
if (message) if (message)
{ {
...@@ -795,7 +806,6 @@ void Explain_select::print_explain_json(Explain_query *query, ...@@ -795,7 +806,6 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->add_member("const_condition"); writer->add_member("const_condition");
write_item(writer, exec_const_cond); write_item(writer, exec_const_cond);
} }
print_explain_json_cache(writer, is_analyze);
Filesort_tracker *first_table_sort= NULL; Filesort_tracker *first_table_sort= NULL;
bool first_table_sort_used= false; bool first_table_sort_used= false;
...@@ -887,6 +897,8 @@ void Explain_select::print_explain_json(Explain_query *query, ...@@ -887,6 +897,8 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->end_object(); writer->end_object();
} }
if (started_cache)
writer->end_object();
} }
......
...@@ -85,7 +85,7 @@ class Explain_node : public Sql_alloc ...@@ -85,7 +85,7 @@ class Explain_node : public Sql_alloc
{ {
public: public:
Explain_node(MEM_ROOT *root) : Explain_node(MEM_ROOT *root) :
cache_stat(NULL), cache_tracker(NULL),
connection_type(EXPLAIN_NODE_OTHER), connection_type(EXPLAIN_NODE_OTHER),
children(root) children(root)
{} {}
...@@ -113,7 +113,7 @@ public: ...@@ -113,7 +113,7 @@ public:
/** /**
expression cache statistics expression cache statistics
*/ */
Expression_cache_stat* cache_stat; Expression_cache_tracker* cache_tracker;
/* /*
How this node is connected to its parent. How this node is connected to its parent.
...@@ -140,7 +140,7 @@ public: ...@@ -140,7 +140,7 @@ public:
uint8 explain_flags, bool is_analyze); uint8 explain_flags, bool is_analyze);
void print_explain_json_for_children(Explain_query *query, void print_explain_json_for_children(Explain_query *query,
Json_writer *writer, bool is_analyze); Json_writer *writer, bool is_analyze);
void print_explain_json_cache(Json_writer *writer, bool is_analyze); bool print_explain_json_cache(Json_writer *writer, bool is_analyze);
virtual ~Explain_node(){} virtual ~Explain_node(){}
}; };
......
...@@ -43,7 +43,7 @@ ulong subquery_cache_miss, subquery_cache_hit; ...@@ -43,7 +43,7 @@ ulong subquery_cache_miss, subquery_cache_hit;
Expression_cache_tmptable::Expression_cache_tmptable(THD *thd, Expression_cache_tmptable::Expression_cache_tmptable(THD *thd,
List<Item> &dependants, List<Item> &dependants,
Item *value) Item *value)
:cache_table(NULL), table_thd(thd), stat(NULL), items(dependants), val(value), :cache_table(NULL), table_thd(thd), tracker(NULL), items(dependants), val(value),
hit(0), miss(0), inited (0) hit(0), miss(0), inited (0)
{ {
DBUG_ENTER("Expression_cache_tmptable::Expression_cache_tmptable"); DBUG_ENTER("Expression_cache_tmptable::Expression_cache_tmptable");
...@@ -61,9 +61,9 @@ void Expression_cache_tmptable::disable_cache() ...@@ -61,9 +61,9 @@ void Expression_cache_tmptable::disable_cache()
cache_table->file->ha_index_end(); cache_table->file->ha_index_end();
free_tmp_table(table_thd, cache_table); free_tmp_table(table_thd, cache_table);
cache_table= NULL; cache_table= NULL;
flush_stat(); update_tracker();
if (stat) if (tracker)
stat->cache= NULL; tracker->cache= NULL;
} }
...@@ -167,7 +167,7 @@ void Expression_cache_tmptable::init() ...@@ -167,7 +167,7 @@ void Expression_cache_tmptable::init()
goto error; goto error;
} }
flush_stat(); update_tracker();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
error: error:
...@@ -186,8 +186,8 @@ Expression_cache_tmptable::~Expression_cache_tmptable() ...@@ -186,8 +186,8 @@ Expression_cache_tmptable::~Expression_cache_tmptable()
disable_cache(); disable_cache();
else else
{ {
flush_stat(); update_tracker();
stat= NULL; tracker= NULL;
} }
} }
...@@ -334,5 +334,5 @@ void Expression_cache_tmptable::print(String *str, enum_query_type query_type) ...@@ -334,5 +334,5 @@ void Expression_cache_tmptable::print(String *str, enum_query_type query_type)
} }
const char *Expression_cache_stat::state_str[3]= const char *Expression_cache_tracker::state_str[3]=
{"UNINITIALYZED", "DISABLED", "ENABLED"}; {"uninitialized", "disabled", "enabled"};
...@@ -65,9 +65,9 @@ public: ...@@ -65,9 +65,9 @@ public:
virtual void init()= 0; virtual void init()= 0;
/** /**
Save this object's statistics into Expression_cache_stat object Save this object's statistics into Expression_cache_tracker object
*/ */
virtual void flush_stat()= 0; virtual void update_tracker()= 0;
}; };
struct st_table_ref; struct st_table_ref;
...@@ -75,11 +75,11 @@ struct st_join_table; ...@@ -75,11 +75,11 @@ struct st_join_table;
class Item_field; class Item_field;
class Expression_cache_stat :public Sql_alloc class Expression_cache_tracker :public Sql_alloc
{ {
public: public:
enum expr_cache_state {UNINITED, STOPPED, OK}; enum expr_cache_state {UNINITED, STOPPED, OK};
Expression_cache_stat(Expression_cache *c) : Expression_cache_tracker(Expression_cache *c) :
cache(c), hit(0), miss(0), state(UNINITED) cache(c), hit(0), miss(0), state(UNINITED)
{} {}
...@@ -91,10 +91,10 @@ public: ...@@ -91,10 +91,10 @@ public:
void set(ulong h, ulong m, enum expr_cache_state s) void set(ulong h, ulong m, enum expr_cache_state s)
{hit= h; miss= m; state= s;} {hit= h; miss= m; state= s;}
void flush_stat() void fetch_current_stats()
{ {
if (cache) if (cache)
cache->flush_stat(); cache->update_tracker();
} }
}; };
...@@ -115,18 +115,20 @@ public: ...@@ -115,18 +115,20 @@ public:
bool is_inited() { return inited; }; bool is_inited() { return inited; };
void init(); void init();
void set_stat(Expression_cache_stat *st) void set_tracker(Expression_cache_tracker *st)
{ {
stat= st; tracker= st;
flush_stat(); update_tracker();
} }
virtual void flush_stat() virtual void update_tracker()
{ {
if (stat) if (tracker)
stat->set(hit, miss, (inited ? (cache_table ? {
Expression_cache_stat::OK : tracker->set(hit, miss, (inited ? (cache_table ?
Expression_cache_stat::STOPPED) : Expression_cache_tracker::OK :
Expression_cache_stat::UNINITED)); Expression_cache_tracker::STOPPED) :
Expression_cache_tracker::UNINITED));
}
} }
private: private:
...@@ -139,7 +141,7 @@ private: ...@@ -139,7 +141,7 @@ private:
/* Thread handle for the temporary table */ /* Thread handle for the temporary table */
THD *table_thd; THD *table_thd;
/* EXPALIN/ANALYZE statistics */ /* EXPALIN/ANALYZE statistics */
Expression_cache_stat *stat; Expression_cache_tracker *tracker;
/* TABLE_REF for index lookup */ /* TABLE_REF for index lookup */
struct st_table_ref ref; struct st_table_ref ref;
/* Cached result */ /* Cached result */
......
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