summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2014-11-29 01:08:18 +0300
committerSergei Petrunia <psergey@askmonty.org>2014-11-29 01:08:18 +0300
commit0b5d989c894a14ebcb786940fafd025e31523d8b (patch)
treed1798a98c1f8f89f9ab9000e2d5e9be4e3e7a845 /sql
parent2ac3b39e68bf6bf1b56e6eafd290c0a78368d0be (diff)
downloadmariadb-git-0b5d989c894a14ebcb786940fafd025e31523d8b.tar.gz
EXPLAIN FORMAT=JSON: Add support for non-merged semi-joins
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_explain.cc26
-rw-r--r--sql/sql_explain.h19
-rw-r--r--sql/sql_lex.cc7
-rw-r--r--sql/sql_select.cc9
-rw-r--r--sql/sql_select.h15
5 files changed, 69 insertions, 7 deletions
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index 37843e8f7d0..4dce48e5944 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -554,6 +554,19 @@ int Explain_node::print_explain_for_children(Explain_query *query,
}
+/*
+ This tells whether a child subquery should be printed in JSON output.
+
+ Derived tables and Non-merged semi-joins should not be printed, because they
+ are printed inline in Explain_table_access.
+*/
+bool is_connection_printable_in_json(enum Explain_node::explain_connection_type type)
+{
+ return (type != Explain_node::EXPLAIN_NODE_DERIVED &&
+ type != Explain_node::EXPLAIN_NODE_NON_MERGED_SJ);
+}
+
+
void Explain_node::print_explain_json_for_children(Explain_query *query,
Json_writer *writer,
bool is_analyze)
@@ -565,7 +578,8 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
{
Explain_node *node= query->get_node(children.at(i));
/* Derived tables are printed inside Explain_table_access objects */
- if (node->is_derived_table)
+
+ if (!is_connection_printable_in_json(node->connection_type))
continue;
if (!started)
@@ -1189,6 +1203,16 @@ void Explain_table_access::print_explain_json(Explain_query *query,
node->print_explain_json(query, writer, is_analyze);
writer->end_object();
}
+ if (non_merged_sjm_number)
+ {
+ /* This is a non-merged semi-join table. Print its contents here */
+ writer->add_member("materialized").start_object();
+ writer->add_member("unique").add_ll(1);
+ Explain_node *node= query->get_node(non_merged_sjm_number);
+ node->connection_type= Explain_node::EXPLAIN_NODE_NON_MERGED_SJ;
+ 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 5b2bf9fdb27..a6a0aff7716 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -77,12 +77,14 @@ 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.
*/
class Explain_node : public Sql_alloc
{
public:
+ /* A type specifying what kind of node this is */
enum explain_node_type
{
EXPLAIN_UNION,
@@ -91,16 +93,24 @@ public:
EXPLAIN_DELETE,
EXPLAIN_INSERT
};
+
+ /* How this node is connected */
+ enum explain_connection_type {
+ EXPLAIN_NODE_OTHER,
+ EXPLAIN_NODE_DERIVED, /* Materialized derived table */
+ EXPLAIN_NODE_NON_MERGED_SJ /* aka JTBM semi-join */
+ };
- Explain_node() : is_derived_table(false) {}
+ Explain_node() : connection_type(EXPLAIN_NODE_OTHER) {}
virtual enum explain_node_type get_type()= 0;
virtual int get_select_id()= 0;
/*
- TRUE means this is a derived table. FALSE means otherwise.
+ How this node is connected to its parent.
+ (NOTE: EXPLAIN_NODE_NON_MERGED_SJ is set very late currently)
*/
- bool is_derived_table;
+ enum explain_connection_type connection_type;
/*
A node may have children nodes. When a node's explain structure is
@@ -502,6 +512,7 @@ class Explain_table_access : public Sql_alloc
public:
Explain_table_access() :
derived_select_number(0),
+ non_merged_sjm_number(0),
where_cond(NULL),
cache_cond(NULL),
pushed_index_cond(NULL)
@@ -525,6 +536,8 @@ public:
find the query plan for the derived table
*/
int derived_select_number;
+ /* TODO: join with the previous member. */
+ int non_merged_sjm_number;
enum join_type type;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index de22788cd7a..4e6c0efdb48 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4268,8 +4268,13 @@ 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;
+ eu->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
+ /*
+ Note: Non-merged semi-joins cannot be made out of UNIONs currently, so we
+ dont ever set EXPLAIN_NODE_NON_MERGED_SJ.
+ */
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 459c770a020..f9cdd08cf68 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -23660,8 +23660,13 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
subselect that used to produce it.
*/
eta->derived_select_number= table->derived_select_number;
+
+ /* The same for non-merged semi-joins */
+ eta->non_merged_sjm_number = get_non_merged_semijoin_select();
}
+
+
/*
Save Query Plan Footprint
@@ -23693,7 +23698,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
xpl_sel->select_type= join->select_lex->type;
xpl_sel->message= message;
if (select_lex->master_unit()->derived)
- xpl_sel->is_derived_table= true;
+ xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
/* Setting xpl_sel->message means that all other members are invalid */
output->add_node(xpl_sel);
}
@@ -23712,7 +23717,7 @@ 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;
if (select_lex->master_unit()->derived)
- xpl_sel->is_derived_table= true;
+ xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS);
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 9463005b2ba..42b2e6b31c2 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -527,6 +527,21 @@ typedef struct st_join_table {
bool preread_init();
bool is_sjm_nest() { return MY_TEST(bush_children); }
+
+ /*
+ If this join_tab reads a non-merged semi-join (also called jtbm), return
+ the select's number. Otherwise, return 0.
+ */
+ int get_non_merged_semijoin_select() const
+ {
+ Item_in_subselect *subq;
+ if (table->pos_in_table_list &&
+ (subq= table->pos_in_table_list->jtbm_subselect))
+ {
+ return subq->unit->first_select()->select_number;
+ }
+ return 0; /* Not a merged semi-join */
+ }
bool access_from_tables_is_allowed(table_map used_tables,
table_map sjm_lookup_tables)