summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2015-07-01 20:03:29 +0300
committerSergei Petrunia <psergey@askmonty.org>2015-07-01 20:03:29 +0300
commit9d2aa2b3093e315f02e42943589f47447c67bbd8 (patch)
treef2f73397e7d6b26e76971e702fbd6a6a01b95521
parentc6aee27b73232fc6ba3e8b55adbb0abba4f0171b (diff)
downloadmariadb-git-9d2aa2b3093e315f02e42943589f47447c67bbd8.tar.gz
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
-rw-r--r--mysql-test/r/subselect_cache.result235
-rw-r--r--sql/item.cc12
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_subselect.cc15
-rw-r--r--sql/item_subselect.h2
-rw-r--r--sql/sql_explain.cc44
-rw-r--r--sql/sql_explain.h6
-rw-r--r--sql/sql_expression_cache.cc18
-rw-r--r--sql/sql_expression_cache.h34
9 files changed, 191 insertions, 179 deletions
diff --git a/mysql-test/r/subselect_cache.result b/mysql-test/r/subselect_cache.result
index 2cf1961ec5b..8ca6bf52e0e 100644
--- a/mysql-test/r/subselect_cache.result
+++ b/mysql-test/r/subselect_cache.result
@@ -59,27 +59,24 @@ ANALYZE
},
"subqueries": [
{
- "query_block": {
- "select_id": 2,
- "r_loops": 4,
- "r_total_time_ms": "REPLACED",
- "expression_cache": {
- "state": "ENABLED",
- "r_hit": 6,
- "r_miss": 4,
- "r_loops": 10,
- "r_hit_ratio": 60
- },
- "table": {
- "table_name": "t2",
- "access_type": "ALL",
+ "expression_cache": {
+ "r_loops": 10,
+ "r_hit_ratio": 60,
+ "query_block": {
+ "select_id": 2,
"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)"
+ "table": {
+ "table_name": "t2",
+ "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
},
"subqueries": [
{
- "query_block": {
- "union_result": {
- "table_name": "<union3,4>",
- "access_type": "ALL",
- "r_loops": 4,
- "r_rows": 1,
- "expression_cache": {
- "state": "ENABLED",
- "r_hit": 6,
- "r_miss": 4,
- "r_loops": 10,
- "r_hit_ratio": 60
- },
- "query_specifications": [
- {
- "query_block": {
- "select_id": 3,
- "r_loops": 4,
- "r_total_time_ms": "REPLACED",
- "table": {
- "table_name": "t2",
- "access_type": "ALL",
+ "expression_cache": {
+ "r_loops": 10,
+ "r_hit_ratio": 60,
+ "query_block": {
+ "union_result": {
+ "table_name": "<union3,4>",
+ "access_type": "ALL",
+ "r_loops": 4,
+ "r_rows": 1,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 3,
"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)"
+ "table": {
+ "table_name": "t2",
+ "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": {
- "select_id": 4,
- "table": {
- "message": "No tables used"
+ },
+ {
+ "query_block": {
+ "select_id": 4,
+ "table": {
+ "message": "No tables used"
+ }
}
}
- }
- ]
+ ]
+ }
}
}
},
{
- "query_block": {
- "select_id": 2,
- "r_loops": 4,
- "r_total_time_ms": "REPLACED",
- "expression_cache": {
- "state": "ENABLED",
- "r_hit": 6,
- "r_miss": 4,
- "r_loops": 10,
- "r_hit_ratio": 60
- },
- "table": {
- "table_name": "t2",
- "access_type": "ALL",
+ "expression_cache": {
+ "r_loops": 10,
+ "r_hit_ratio": 60,
+ "query_block": {
+ "select_id": 2,
"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)"
+ "table": {
+ "table_name": "t2",
+ "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
},
"subqueries": [
{
- "query_block": {
- "select_id": 2,
- "expression_cache": {
- "state": "UNINITIALYZED"
- },
- "table": {
- "table_name": "t2",
- "access_type": "ALL",
- "rows": 4,
- "filtered": 100,
- "attached_condition": "(t1.b = t2.c)"
+ "expression_cache": {
+ "state": "uninitialized",
+ "query_block": {
+ "select_id": 2,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "(t1.b = t2.c)"
+ }
}
}
}
@@ -223,50 +214,50 @@ EXPLAIN
},
"subqueries": [
{
- "query_block": {
- "union_result": {
- "table_name": "<union3,4>",
- "access_type": "ALL",
- "expression_cache": {
- "state": "UNINITIALYZED"
- },
- "query_specifications": [
- {
- "query_block": {
- "select_id": 3,
- "table": {
- "table_name": "t2",
- "access_type": "ALL",
- "rows": 4,
- "filtered": 100,
- "attached_condition": "(t1.b = t2.c)"
+ "expression_cache": {
+ "state": "uninitialized",
+ "query_block": {
+ "union_result": {
+ "table_name": "<union3,4>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 3,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "(t1.b = t2.c)"
+ }
}
- }
- },
- {
- "query_block": {
- "select_id": 4,
- "table": {
- "message": "No tables used"
+ },
+ {
+ "query_block": {
+ "select_id": 4,
+ "table": {
+ "message": "No tables used"
+ }
}
}
- }
- ]
+ ]
+ }
}
}
},
{
- "query_block": {
- "select_id": 2,
- "expression_cache": {
- "state": "UNINITIALYZED"
- },
- "table": {
- "table_name": "t2",
- "access_type": "ALL",
- "rows": 4,
- "filtered": 100,
- "attached_condition": "(t1.b = t2.c)"
+ "expression_cache": {
+ "state": "uninitialized",
+ "query_block": {
+ "select_id": 2,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "(t1.b = t2.c)"
+ }
}
}
}
diff --git a/sql/item.cc b/sql/item.cc
index 14e14968278..f8365226a76 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -7554,15 +7554,15 @@ bool Item_cache_wrapper::set_cache(THD *thd)
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)
{
- Expression_cache_stat* stat=
- new(mem_root) Expression_cache_stat(expr_cache);
- if (stat)
- ((Expression_cache_tmptable *)expr_cache)->set_stat(stat);
- return stat;
+ Expression_cache_tracker* tracker=
+ new(mem_root) Expression_cache_tracker(expr_cache);
+ if (tracker)
+ ((Expression_cache_tmptable *)expr_cache)->set_tracker(tracker);
+ return tracker;
}
return NULL;
}
diff --git a/sql/item.h b/sql/item.h
index cecc0f24514..88c02a67f9b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -3804,7 +3804,7 @@ public:
class Item_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.
@@ -3839,7 +3839,7 @@ public:
enum Type real_type() const { return orig_item->type(); }
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);
void cleanup();
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 0b90063f9cb..fa2549a0bd5 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1202,7 +1202,7 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(uchar *thd_arg)
if (expr_cache_is_needed(thd) &&
(expr_cache= set_expr_cache(thd)))
{
- set_expr_cache_stat(thd);
+ init_expr_cache_tracker(thd);
DBUG_RETURN(expr_cache);
}
DBUG_RETURN(this);
@@ -1501,7 +1501,7 @@ Item* Item_exists_subselect::expr_cache_insert_transformer(uchar *thd_arg)
if (substype() == EXISTS_SUBS && expr_cache_is_needed(thd) &&
(expr_cache= set_expr_cache(thd)))
{
- set_expr_cache_stat(thd);
+ init_expr_cache_tracker(thd);
DBUG_RETURN(expr_cache);
}
DBUG_RETURN(this);
@@ -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)
return;
@@ -6573,5 +6579,6 @@ void Item_subselect::set_expr_cache_stat(THD *thd)
if (!node)
return;
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);
}
+
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index cad66cd3442..1930493b6b9 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -246,7 +246,7 @@ public:
return TRUE;
}
- void set_expr_cache_stat(THD *thd);
+ void init_expr_cache_tracker(THD *thd);
friend class select_result_interceptor;
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index 210700a2804..9f4b635fbf4 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -521,6 +521,8 @@ void Explain_union::print_explain_json(Explain_query *query,
Json_writer_nesting_guard guard(writer);
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("union_result").start_object();
// using_temporary_table
@@ -544,7 +546,6 @@ void Explain_union::print_explain_json(Explain_query *query,
writer->add_null();
}
- print_explain_json_cache(writer, is_analyze);
writer->add_member("query_specifications").start_array();
for (int i= 0; i < (int) union_members.elements(); i++)
@@ -562,6 +563,9 @@ void Explain_union::print_explain_json(Explain_query *query,
writer->end_object(); // union_result
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,
}
-void Explain_node::print_explain_json_cache(Json_writer *writer,
+bool Explain_node::print_explain_json_cache(Json_writer *writer,
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").
- add_str(Expression_cache_stat::state_str[cache_stat->state]);
- if (is_analyze)
+ add_str(Expression_cache_tracker::state_str[cache_tracker->state]);
+ }
+
+ 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);
- writer->add_member("r_miss").add_ll(cache_stat->miss);
- 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);
+ double hit_ratio= double(cache_tracker->hit) / cache_reads * 100.0;
+ writer->add_member("r_hit_ratio").add_double(hit_ratio);
}
- writer->end_object();
}
+ return true;
+ }
+ return false;
}
@@ -766,6 +775,8 @@ void Explain_select::print_explain_json(Explain_query *query,
Json_writer *writer, bool is_analyze)
{
Json_writer_nesting_guard guard(writer);
+
+ bool started_cache= print_explain_json_cache(writer, is_analyze);
if (message)
{
@@ -795,7 +806,6 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->add_member("const_condition");
write_item(writer, exec_const_cond);
}
- print_explain_json_cache(writer, is_analyze);
Filesort_tracker *first_table_sort= NULL;
bool first_table_sort_used= false;
@@ -887,6 +897,8 @@ void Explain_select::print_explain_json(Explain_query *query,
writer->end_object();
}
+ if (started_cache)
+ writer->end_object();
}
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 427553c1088..1b6a1be5649 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -85,7 +85,7 @@ class Explain_node : public Sql_alloc
{
public:
Explain_node(MEM_ROOT *root) :
- cache_stat(NULL),
+ cache_tracker(NULL),
connection_type(EXPLAIN_NODE_OTHER),
children(root)
{}
@@ -113,7 +113,7 @@ public:
/**
expression cache statistics
*/
- Expression_cache_stat* cache_stat;
+ Expression_cache_tracker* cache_tracker;
/*
How this node is connected to its parent.
@@ -140,7 +140,7 @@ public:
uint8 explain_flags, bool is_analyze);
void print_explain_json_for_children(Explain_query *query,
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(){}
};
diff --git a/sql/sql_expression_cache.cc b/sql/sql_expression_cache.cc
index bda0aaafebe..cc922c3bcfe 100644
--- a/sql/sql_expression_cache.cc
+++ b/sql/sql_expression_cache.cc
@@ -43,7 +43,7 @@ ulong subquery_cache_miss, subquery_cache_hit;
Expression_cache_tmptable::Expression_cache_tmptable(THD *thd,
List<Item> &dependants,
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)
{
DBUG_ENTER("Expression_cache_tmptable::Expression_cache_tmptable");
@@ -61,9 +61,9 @@ void Expression_cache_tmptable::disable_cache()
cache_table->file->ha_index_end();
free_tmp_table(table_thd, cache_table);
cache_table= NULL;
- flush_stat();
- if (stat)
- stat->cache= NULL;
+ update_tracker();
+ if (tracker)
+ tracker->cache= NULL;
}
@@ -167,7 +167,7 @@ void Expression_cache_tmptable::init()
goto error;
}
- flush_stat();
+ update_tracker();
DBUG_VOID_RETURN;
error:
@@ -186,8 +186,8 @@ Expression_cache_tmptable::~Expression_cache_tmptable()
disable_cache();
else
{
- flush_stat();
- stat= NULL;
+ update_tracker();
+ tracker= NULL;
}
}
@@ -334,5 +334,5 @@ void Expression_cache_tmptable::print(String *str, enum_query_type query_type)
}
-const char *Expression_cache_stat::state_str[3]=
-{"UNINITIALYZED", "DISABLED", "ENABLED"};
+const char *Expression_cache_tracker::state_str[3]=
+{"uninitialized", "disabled", "enabled"};
diff --git a/sql/sql_expression_cache.h b/sql/sql_expression_cache.h
index 33c67f8eaca..87be6ddb4f4 100644
--- a/sql/sql_expression_cache.h
+++ b/sql/sql_expression_cache.h
@@ -65,9 +65,9 @@ public:
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;
@@ -75,11 +75,11 @@ struct st_join_table;
class Item_field;
-class Expression_cache_stat :public Sql_alloc
+class Expression_cache_tracker :public Sql_alloc
{
public:
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)
{}
@@ -91,10 +91,10 @@ public:
void set(ulong h, ulong m, enum expr_cache_state s)
{hit= h; miss= m; state= s;}
- void flush_stat()
+ void fetch_current_stats()
{
if (cache)
- cache->flush_stat();
+ cache->update_tracker();
}
};
@@ -115,18 +115,20 @@ public:
bool is_inited() { return inited; };
void init();
- void set_stat(Expression_cache_stat *st)
+ void set_tracker(Expression_cache_tracker *st)
{
- stat= st;
- flush_stat();
+ tracker= st;
+ update_tracker();
}
- virtual void flush_stat()
+ virtual void update_tracker()
{
- if (stat)
- stat->set(hit, miss, (inited ? (cache_table ?
- Expression_cache_stat::OK :
- Expression_cache_stat::STOPPED) :
- Expression_cache_stat::UNINITED));
+ if (tracker)
+ {
+ tracker->set(hit, miss, (inited ? (cache_table ?
+ Expression_cache_tracker::OK :
+ Expression_cache_tracker::STOPPED) :
+ Expression_cache_tracker::UNINITED));
+ }
}
private:
@@ -139,7 +141,7 @@ private:
/* Thread handle for the temporary table */
THD *table_thd;
/* EXPALIN/ANALYZE statistics */
- Expression_cache_stat *stat;
+ Expression_cache_tracker *tracker;
/* TABLE_REF for index lookup */
struct st_table_ref ref;
/* Cached result */