[Commits] 2ac3b39: EXPLAIN FORMAT=JSON: support derived tables

Sergei Petrunia psergey at askmonty.org
Fri Nov 28 21:23:29 EET 2014


revision-id: 2ac3b39e68bf6bf1b56e6eafd290c0a78368d0be
parent(s): 3a5e080d4dbe58675e6324eaa807bc2c7aa8795d
committer: Sergei Petrunia
branch nick: 10.1-explain-json-r5
timestamp: 2014-11-28 22:23:29 +0300
message:

EXPLAIN FORMAT=JSON: support derived tables

---
 mysql-test/r/explain_json.result |   71 ++++++++++++++++++++++++++++++++++++++
 mysql-test/t/explain_json.test   |   13 +++++++
 sql/sql_explain.cc               |   37 +++++++++++++++-----
 sql/sql_explain.h                |   17 ++++++++-
 sql/sql_lex.cc                   |    2 ++
 sql/sql_select.cc                |   10 ++++++
 6 files changed, 141 insertions(+), 9 deletions(-)

diff --git a/mysql-test/r/explain_json.result b/mysql-test/r/explain_json.result
index d97abba..416f432 100644
--- a/mysql-test/r/explain_json.result
+++ b/mysql-test/r/explain_json.result
@@ -393,4 +393,75 @@ EXPLAIN
     }
   }
 }
+#
+# A derived table
+#
+create table t1 (a int, b int);
+insert into t1 select a,a from t0;
+explain format=json
+select * from (select a, count(*) as cnt from t1 group by a) as tbl
+where cnt>0;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "table_name": "<derived2>",
+      "access_type": "ALL",
+      "rows": 10,
+      "filtered": 100,
+      "attached_condition": "(tbl.cnt > 0)",
+      "materialized": {
+        "query_block": {
+          "select_id": 2,
+          "table": {
+            "table_name": "t1",
+            "access_type": "ALL",
+            "rows": 10,
+            "filtered": 100
+          }
+        }
+      }
+    }
+  }
+}
+explain format=json
+select * from (select a, count(*) as cnt from t1 group by a) as tbl1, t1 as
+tbl2 where cnt=tbl2.a;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "table_name": "tbl2",
+      "access_type": "ALL",
+      "rows": 10,
+      "filtered": 100,
+      "attached_condition": "(tbl2.a is not null)"
+    },
+    "table": {
+      "table_name": "<derived2>",
+      "access_type": "ref",
+      "possible_keys": ["key0"],
+      "key": "key0",
+      "key_length": "8",
+      "used_key_parts": ["cnt"],
+      "ref": ["test.tbl2.a"],
+      "rows": 2,
+      "filtered": 100,
+      "attached_condition": "(tbl1.cnt = tbl2.a)",
+      "materialized": {
+        "query_block": {
+          "select_id": 2,
+          "table": {
+            "table_name": "t1",
+            "access_type": "ALL",
+            "rows": 10,
+            "filtered": 100
+          }
+        }
+      }
+    }
+  }
+}
 drop table t0;
diff --git a/mysql-test/t/explain_json.test b/mysql-test/t/explain_json.test
index 3917ce4..8631d85 100644
--- a/mysql-test/t/explain_json.test
+++ b/mysql-test/t/explain_json.test
@@ -80,5 +80,18 @@ explain format=json delete from t0 where a < 3;
 
 explain format=json update t0 set a=3 where a in (2,3,4);
 
+--echo #
+--echo # A derived table
+--echo #
+create table t1 (a int, b int);
+insert into t1 select a,a from t0;
+explain format=json
+select * from (select a, count(*) as cnt from t1 group by a) as tbl
+where cnt>0;
+
+explain format=json
+select * from (select a, count(*) as cnt from t1 group by a) as tbl1, t1 as
+tbl2 where cnt=tbl2.a;
+
 drop table t0;
 
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index f8a45b5..37843e8 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -558,18 +558,29 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
                                                   Json_writer *writer,
                                                   bool is_analyze)
 {
-  if (!children.elements())
-    return;
-
-  writer->add_member("subqueries").start_array();
+  Json_writer_nesting_guard guard(writer);
+  
+  bool started= false;
   for (int i= 0; i < (int) children.elements(); i++)
   {
-    writer->start_object();
     Explain_node *node= query->get_node(children.at(i));
+    /* Derived tables are printed inside Explain_table_access objects */
+    if (node->is_derived_table)
+      continue;
+
+    if (!started)
+    {
+      writer->add_member("subqueries").start_array();
+      started= true;
+    }
+
+    writer->start_object();
     node->print_explain_json(query, writer, is_analyze);
     writer->end_object();
   }
-  writer->end_array();
+
+  if (started)
+    writer->end_array();
 }
 
 
@@ -665,7 +676,7 @@ void Explain_select::print_explain_json(Explain_query *query,
     for (uint i=0; i< n_join_tabs; i++)
     {
       // psergey-todo: Need to honor SJM nests...
-      join_tabs[i]->print_explain_json(writer, is_analyze);
+      join_tabs[i]->print_explain_json(query, writer, is_analyze);
     }
   }
 
@@ -1054,7 +1065,8 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t
 }
 
 
-void Explain_table_access::print_explain_json(Json_writer *writer, 
+void Explain_table_access::print_explain_json(Explain_query *query,
+                                              Json_writer *writer,
                                               bool is_analyze)
 {
   Json_writer_nesting_guard guard(writer);
@@ -1169,6 +1181,15 @@ void Explain_table_access::print_explain_json(Json_writer *writer,
     }
   }
 
+  if (derived_select_number)
+  {
+    /* This is a derived table. Print its contents here */
+    writer->add_member("materialized").start_object();
+    Explain_node *node= query->get_node(derived_select_number);
+    node->print_explain_json(query, writer, is_analyze);
+    writer->end_object();
+  }
+
   writer->end_object();
 }
 
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 5fd1d5e..5b2bf9f 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -92,9 +92,16 @@ class Explain_node : public Sql_alloc
     EXPLAIN_INSERT
   };
 
+  Explain_node() : is_derived_table(false) {}
+
   virtual enum explain_node_type get_type()= 0;
   virtual int get_select_id()= 0;
 
+  /*
+    TRUE means this is a derived table. FALSE means otherwise.
+  */
+  bool is_derived_table;
+
   /* 
     A node may have children nodes. When a node's explain structure is 
     created, children nodes may not yet have QPFs. This is why we store ids.
@@ -494,6 +501,7 @@ class Explain_table_access : public Sql_alloc
 {
 public:
   Explain_table_access() :
+    derived_select_number(0),
     where_cond(NULL),
     cache_cond(NULL),
     pushed_index_cond(NULL)
@@ -512,6 +520,12 @@ class Explain_table_access : public Sql_alloc
   /* id and 'select_type' are cared-of by the parent Explain_select */
   StringBuffer<32> table_name;
 
+  /* 
+    Non-zero number means this is a derived table. The number can be used to
+    find the query plan for the derived table
+  */
+  int derived_select_number;
+
   enum join_type type;
 
   StringBuffer<32> used_partitions;
@@ -581,7 +595,8 @@ class Explain_table_access : public Sql_alloc
                     bool is_analyze,
                     uint select_id, const char *select_type,
                     bool using_temporary, bool using_filesort);
-  void print_explain_json(Json_writer *writer, bool is_analyze);
+  void print_explain_json(Explain_query *query, Json_writer *writer,
+                          bool is_analyze);
 
   /* ANALYZE members*/
   Table_access_tracker tracker;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 7441f46..de22788 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4268,6 +4268,8 @@ int st_select_lex_unit::save_union_explain(Explain_query *output)
 {
   SELECT_LEX *first= first_select();
   Explain_union *eu= new (output->mem_root) Explain_union;
+  if (derived)
+    eu->is_derived_table= true;
 
   for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
     eu->add_select(sl->select_number);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f66525d..459c770 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -23654,6 +23654,12 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
       tab->cache->save_explain_data(&eta->bka_type);
     }
   }
+
+  /* 
+    In case this is a derived table, here we remember the number of 
+    subselect that used to produce it.
+  */
+  eta->derived_select_number= table->derived_select_number;
 }
 
 /*
@@ -23686,6 +23692,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
     xpl_sel->select_id= join->select_lex->select_number;
     xpl_sel->select_type= join->select_lex->type;
     xpl_sel->message= message;
+    if (select_lex->master_unit()->derived)
+      xpl_sel->is_derived_table= true;
     /* Setting xpl_sel->message means that all other members are invalid */
     output->add_node(xpl_sel);
   }
@@ -23703,6 +23711,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
     join->select_lex->set_explain_type(true);
     xpl_sel->select_id= join->select_lex->select_number;
     xpl_sel->select_type= join->select_lex->type;
+    if (select_lex->master_unit()->derived)
+      xpl_sel->is_derived_table= true;
 
     JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS);
 


More information about the commits mailing list