Commit 0b5d989c authored by Sergei Petrunia's avatar Sergei Petrunia

EXPLAIN FORMAT=JSON: Add support for non-merged semi-joins

parent 2ac3b39e
...@@ -464,4 +464,46 @@ EXPLAIN ...@@ -464,4 +464,46 @@ EXPLAIN
} }
} }
} }
#
# Non-merged semi-join (aka JTBM)
#
explain format=json
select * from t1 where a in (select max(a) from t1 group by b);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100,
"attached_condition": "(t1.a is not null)"
},
"table": {
"table_name": "<subquery2>",
"access_type": "eq_ref",
"possible_keys": ["distinct_key"],
"key": "distinct_key",
"key_length": "4",
"used_key_parts": ["max(a)"],
"ref": ["test.t1.a"],
"rows": 1,
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
}
drop table t1;
drop table t0; drop table t0;
...@@ -93,5 +93,11 @@ explain format=json ...@@ -93,5 +93,11 @@ explain format=json
select * from (select a, count(*) as cnt from t1 group by a) as tbl1, t1 as select * from (select a, count(*) as cnt from t1 group by a) as tbl1, t1 as
tbl2 where cnt=tbl2.a; tbl2 where cnt=tbl2.a;
--echo #
--echo # Non-merged semi-join (aka JTBM)
--echo #
explain format=json
select * from t1 where a in (select max(a) from t1 group by b);
drop table t1;
drop table t0; drop table t0;
...@@ -554,6 +554,19 @@ int Explain_node::print_explain_for_children(Explain_query *query, ...@@ -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, void Explain_node::print_explain_json_for_children(Explain_query *query,
Json_writer *writer, Json_writer *writer,
bool is_analyze) bool is_analyze)
...@@ -565,7 +578,8 @@ void Explain_node::print_explain_json_for_children(Explain_query *query, ...@@ -565,7 +578,8 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
{ {
Explain_node *node= query->get_node(children.at(i)); Explain_node *node= query->get_node(children.at(i));
/* Derived tables are printed inside Explain_table_access objects */ /* Derived tables are printed inside Explain_table_access objects */
if (node->is_derived_table)
if (!is_connection_printable_in_json(node->connection_type))
continue; continue;
if (!started) if (!started)
...@@ -1189,6 +1203,16 @@ void Explain_table_access::print_explain_json(Explain_query *query, ...@@ -1189,6 +1203,16 @@ void Explain_table_access::print_explain_json(Explain_query *query,
node->print_explain_json(query, writer, is_analyze); node->print_explain_json(query, writer, is_analyze);
writer->end_object(); 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(); writer->end_object();
} }
......
...@@ -77,12 +77,14 @@ const int FAKE_SELECT_LEX_ID= (int)UINT_MAX; ...@@ -77,12 +77,14 @@ const int FAKE_SELECT_LEX_ID= (int)UINT_MAX;
class Explain_query; class Explain_query;
class Json_writer; class Json_writer;
/* /*
A node can be either a SELECT, or a UNION. A node can be either a SELECT, or a UNION.
*/ */
class Explain_node : public Sql_alloc class Explain_node : public Sql_alloc
{ {
public: public:
/* A type specifying what kind of node this is */
enum explain_node_type enum explain_node_type
{ {
EXPLAIN_UNION, EXPLAIN_UNION,
...@@ -91,16 +93,24 @@ public: ...@@ -91,16 +93,24 @@ public:
EXPLAIN_DELETE, EXPLAIN_DELETE,
EXPLAIN_INSERT 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 enum explain_node_type get_type()= 0;
virtual int get_select_id()= 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 A node may have children nodes. When a node's explain structure is
...@@ -502,6 +512,7 @@ class Explain_table_access : public Sql_alloc ...@@ -502,6 +512,7 @@ class Explain_table_access : public Sql_alloc
public: public:
Explain_table_access() : Explain_table_access() :
derived_select_number(0), derived_select_number(0),
non_merged_sjm_number(0),
where_cond(NULL), where_cond(NULL),
cache_cond(NULL), cache_cond(NULL),
pushed_index_cond(NULL) pushed_index_cond(NULL)
...@@ -525,6 +536,8 @@ public: ...@@ -525,6 +536,8 @@ public:
find the query plan for the derived table find the query plan for the derived table
*/ */
int derived_select_number; int derived_select_number;
/* TODO: join with the previous member. */
int non_merged_sjm_number;
enum join_type type; enum join_type type;
......
...@@ -4268,8 +4268,13 @@ int st_select_lex_unit::save_union_explain(Explain_query *output) ...@@ -4268,8 +4268,13 @@ int st_select_lex_unit::save_union_explain(Explain_query *output)
{ {
SELECT_LEX *first= first_select(); SELECT_LEX *first= first_select();
Explain_union *eu= new (output->mem_root) Explain_union; Explain_union *eu= new (output->mem_root) Explain_union;
if (derived) 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()) for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
eu->add_select(sl->select_number); eu->add_select(sl->select_number);
......
...@@ -23660,8 +23660,13 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab ...@@ -23660,8 +23660,13 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
subselect that used to produce it. subselect that used to produce it.
*/ */
eta->derived_select_number= table->derived_select_number; 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 Save Query Plan Footprint
...@@ -23693,7 +23698,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table, ...@@ -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->select_type= join->select_lex->type;
xpl_sel->message= message; xpl_sel->message= message;
if (select_lex->master_unit()->derived) 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 */ /* Setting xpl_sel->message means that all other members are invalid */
output->add_node(xpl_sel); output->add_node(xpl_sel);
} }
...@@ -23712,7 +23717,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table, ...@@ -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_id= join->select_lex->select_number;
xpl_sel->select_type= join->select_lex->type; xpl_sel->select_type= join->select_lex->type;
if (select_lex->master_unit()->derived) 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); JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS);
......
...@@ -527,6 +527,21 @@ typedef struct st_join_table { ...@@ -527,6 +527,21 @@ typedef struct st_join_table {
bool preread_init(); bool preread_init();
bool is_sjm_nest() { return MY_TEST(bush_children); } 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, bool access_from_tables_is_allowed(table_map used_tables,
table_map sjm_lookup_tables) table_map sjm_lookup_tables)
......
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