mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
EXPLAIN FORMAT=JSON
Add support for semi-join strategies: FirstMatch, DuplicateWeedout, LooseScan.
This commit is contained in:
@ -592,5 +592,77 @@ EXPLAIN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#
|
||||||
|
# First-Match
|
||||||
|
#
|
||||||
|
explain
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 ALL NULL NULL NULL NULL 10
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; FirstMatch(t2); Using join buffer (flat, BNL join)
|
||||||
|
explain format=json
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100
|
||||||
|
},
|
||||||
|
"block-nl-join": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "t1",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100,
|
||||||
|
"first_match": "t2"
|
||||||
|
},
|
||||||
|
"buffer_type": "flat",
|
||||||
|
"join_type": "BNL",
|
||||||
|
"attached_condition": "((t1.b = t2.b) and (t1.a = t2.a))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#
|
||||||
|
# Duplicate Weedout
|
||||||
|
#
|
||||||
|
set @tmp= @@optimizer_switch;
|
||||||
|
set optimizer_switch='firstmatch=off';
|
||||||
|
explain
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 ALL NULL NULL NULL NULL 10
|
||||||
|
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join)
|
||||||
|
explain format=json
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100
|
||||||
|
},
|
||||||
|
"duplicates_removal": {
|
||||||
|
"block-nl-join": {
|
||||||
|
"table": {
|
||||||
|
"table_name": "t1",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100
|
||||||
|
},
|
||||||
|
"buffer_type": "flat",
|
||||||
|
"join_type": "BNL",
|
||||||
|
"attached_condition": "((t1.b = t2.b) and (t1.a = t2.a))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set optimizer_switch=@tmp;
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
drop table t0;
|
drop table t0;
|
||||||
|
@ -114,6 +114,25 @@ insert into t2 select * from t1;
|
|||||||
explain format=json
|
explain format=json
|
||||||
select * from t1,t2 where t1.a in ( select a from t0);
|
select * from t1,t2 where t1.a in ( select a from t0);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # First-Match
|
||||||
|
--echo #
|
||||||
|
explain
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
explain format=json
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Duplicate Weedout
|
||||||
|
--echo #
|
||||||
|
set @tmp= @@optimizer_switch;
|
||||||
|
set optimizer_switch='firstmatch=off';
|
||||||
|
explain
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
explain format=json
|
||||||
|
select * from t2 where t2.a in ( select a from t1 where t1.b=t2.b);
|
||||||
|
set optimizer_switch=@tmp;
|
||||||
|
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
drop table t0;
|
drop table t0;
|
||||||
|
|
||||||
|
@ -732,7 +732,13 @@ void Explain_basic_join::print_explain_json(Explain_query *query,
|
|||||||
writer->add_member("select_id").add_ll(select_id);
|
writer->add_member("select_id").add_ll(select_id);
|
||||||
for (uint i=0; i< n_join_tabs; i++)
|
for (uint i=0; i< n_join_tabs; i++)
|
||||||
{
|
{
|
||||||
|
if (join_tabs[i]->start_dups_weedout)
|
||||||
|
writer->add_member("duplicates_removal").start_object();
|
||||||
|
|
||||||
join_tabs[i]->print_explain_json(query, writer, is_analyze);
|
join_tabs[i]->print_explain_json(query, writer, is_analyze);
|
||||||
|
|
||||||
|
if (join_tabs[i]->end_dups_weedout)
|
||||||
|
writer->end_object();
|
||||||
}
|
}
|
||||||
print_explain_json_for_children(query, writer, is_analyze);
|
print_explain_json_for_children(query, writer, is_analyze);
|
||||||
writer->end_object();
|
writer->end_object();
|
||||||
@ -1089,9 +1095,7 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t
|
|||||||
write_item(writer, pushed_index_cond);
|
write_item(writer, pushed_index_cond);
|
||||||
break;
|
break;
|
||||||
case ET_USING_WHERE:
|
case ET_USING_WHERE:
|
||||||
if (where_cond)
|
|
||||||
{
|
{
|
||||||
writer->add_member("attached_condition");
|
|
||||||
/*
|
/*
|
||||||
We are printing the condition that is checked when scanning this
|
We are printing the condition that is checked when scanning this
|
||||||
table.
|
table.
|
||||||
@ -1099,7 +1103,11 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t
|
|||||||
- in other cases, it is where_cond.
|
- in other cases, it is where_cond.
|
||||||
*/
|
*/
|
||||||
Item *item= bka_type.is_using_jbuf()? cache_cond: where_cond;
|
Item *item= bka_type.is_using_jbuf()? cache_cond: where_cond;
|
||||||
write_item(writer, item);
|
if (item)
|
||||||
|
{
|
||||||
|
writer->add_member("attached_condition");
|
||||||
|
write_item(writer, item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ET_USING_INDEX:
|
case ET_USING_INDEX:
|
||||||
@ -1110,6 +1118,15 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t
|
|||||||
break;
|
break;
|
||||||
case ET_USING_JOIN_BUFFER:
|
case ET_USING_JOIN_BUFFER:
|
||||||
/* Do nothing. Join buffer is handled differently */
|
/* Do nothing. Join buffer is handled differently */
|
||||||
|
case ET_START_TEMPORARY:
|
||||||
|
case ET_END_TEMPORARY:
|
||||||
|
/* Handled as "duplicates_removal: { ... } */
|
||||||
|
break;
|
||||||
|
case ET_FIRST_MATCH:
|
||||||
|
writer->add_member("first_match").add_str(firstmatch_table_name.c_ptr());
|
||||||
|
break;
|
||||||
|
case ET_LOOSESCAN:
|
||||||
|
writer->add_member("loose_scan").add_bool(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
|
@ -539,6 +539,8 @@ public:
|
|||||||
Explain_table_access() :
|
Explain_table_access() :
|
||||||
derived_select_number(0),
|
derived_select_number(0),
|
||||||
non_merged_sjm_number(0),
|
non_merged_sjm_number(0),
|
||||||
|
start_dups_weedout(false),
|
||||||
|
end_dups_weedout(false),
|
||||||
where_cond(NULL),
|
where_cond(NULL),
|
||||||
cache_cond(NULL),
|
cache_cond(NULL),
|
||||||
pushed_index_cond(NULL),
|
pushed_index_cond(NULL),
|
||||||
@ -615,6 +617,9 @@ public:
|
|||||||
EXPLAIN_BKA_TYPE bka_type;
|
EXPLAIN_BKA_TYPE bka_type;
|
||||||
|
|
||||||
StringBuffer<32> firstmatch_table_name;
|
StringBuffer<32> firstmatch_table_name;
|
||||||
|
|
||||||
|
bool start_dups_weedout;
|
||||||
|
bool end_dups_weedout;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note: lifespan of WHERE condition is less than lifespan of this object.
|
Note: lifespan of WHERE condition is less than lifespan of this object.
|
||||||
|
@ -23641,9 +23641,16 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tab->first_weedout_table)
|
if (tab->first_weedout_table)
|
||||||
|
{
|
||||||
|
eta->start_dups_weedout= true;
|
||||||
eta->push_extra(ET_START_TEMPORARY);
|
eta->push_extra(ET_START_TEMPORARY);
|
||||||
|
}
|
||||||
if (tab->check_weed_out_table)
|
if (tab->check_weed_out_table)
|
||||||
|
{
|
||||||
eta->push_extra(ET_END_TEMPORARY);
|
eta->push_extra(ET_END_TEMPORARY);
|
||||||
|
eta->end_dups_weedout= true;
|
||||||
|
}
|
||||||
|
|
||||||
else if (tab->do_firstmatch)
|
else if (tab->do_firstmatch)
|
||||||
{
|
{
|
||||||
if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1)
|
if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1)
|
||||||
|
Reference in New Issue
Block a user