mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
EXPLAIN FORMAT=JSON: support derived tables
This commit is contained in:
@ -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;
|
drop table t0;
|
||||||
|
@ -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);
|
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;
|
drop table t0;
|
||||||
|
|
||||||
|
@ -558,18 +558,29 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
|
|||||||
Json_writer *writer,
|
Json_writer *writer,
|
||||||
bool is_analyze)
|
bool is_analyze)
|
||||||
{
|
{
|
||||||
if (!children.elements())
|
Json_writer_nesting_guard guard(writer);
|
||||||
return;
|
|
||||||
|
|
||||||
writer->add_member("subqueries").start_array();
|
bool started= false;
|
||||||
for (int i= 0; i < (int) children.elements(); i++)
|
for (int i= 0; i < (int) children.elements(); i++)
|
||||||
{
|
{
|
||||||
writer->start_object();
|
|
||||||
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 */
|
||||||
|
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);
|
node->print_explain_json(query, writer, is_analyze);
|
||||||
writer->end_object();
|
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++)
|
for (uint i=0; i< n_join_tabs; i++)
|
||||||
{
|
{
|
||||||
// psergey-todo: Need to honor SJM nests...
|
// 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)
|
bool is_analyze)
|
||||||
{
|
{
|
||||||
Json_writer_nesting_guard guard(writer);
|
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();
|
writer->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +92,16 @@ public:
|
|||||||
EXPLAIN_INSERT
|
EXPLAIN_INSERT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Explain_node() : is_derived_table(false) {}
|
||||||
|
|
||||||
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.
|
||||||
|
*/
|
||||||
|
bool is_derived_table;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
||||||
created, children nodes may not yet have QPFs. This is why we store ids.
|
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:
|
public:
|
||||||
Explain_table_access() :
|
Explain_table_access() :
|
||||||
|
derived_select_number(0),
|
||||||
where_cond(NULL),
|
where_cond(NULL),
|
||||||
cache_cond(NULL),
|
cache_cond(NULL),
|
||||||
pushed_index_cond(NULL)
|
pushed_index_cond(NULL)
|
||||||
@ -512,6 +520,12 @@ public:
|
|||||||
/* id and 'select_type' are cared-of by the parent Explain_select */
|
/* id and 'select_type' are cared-of by the parent Explain_select */
|
||||||
StringBuffer<32> table_name;
|
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;
|
enum join_type type;
|
||||||
|
|
||||||
StringBuffer<32> used_partitions;
|
StringBuffer<32> used_partitions;
|
||||||
@ -581,7 +595,8 @@ public:
|
|||||||
bool is_analyze,
|
bool is_analyze,
|
||||||
uint select_id, const char *select_type,
|
uint select_id, const char *select_type,
|
||||||
bool using_temporary, bool using_filesort);
|
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*/
|
/* ANALYZE members*/
|
||||||
Table_access_tracker tracker;
|
Table_access_tracker tracker;
|
||||||
|
@ -4268,6 +4268,8 @@ 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)
|
||||||
|
eu->is_derived_table= true;
|
||||||
|
|
||||||
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);
|
||||||
|
@ -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);
|
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_id= join->select_lex->select_number;
|
||||||
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)
|
||||||
|
xpl_sel->is_derived_table= true;
|
||||||
/* 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);
|
||||||
}
|
}
|
||||||
@ -23703,6 +23711,8 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
|
|||||||
join->select_lex->set_explain_type(true);
|
join->select_lex->set_explain_type(true);
|
||||||
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)
|
||||||
|
xpl_sel->is_derived_table= true;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user