diff --git a/mysql-test/r/explain_json.result b/mysql-test/r/explain_json.result index 4a45e8d7594..c159161a8bd 100644 --- a/mysql-test/r/explain_json.result +++ b/mysql-test/r/explain_json.result @@ -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 t0; diff --git a/mysql-test/t/explain_json.test b/mysql-test/t/explain_json.test index 2f5c24ab5a5..20c5359e646 100644 --- a/mysql-test/t/explain_json.test +++ b/mysql-test/t/explain_json.test @@ -114,6 +114,25 @@ insert into t2 select * from t1; explain format=json 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 t0; diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index c4f8002494f..7e6c1c6cf5c 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -732,7 +732,13 @@ void Explain_basic_join::print_explain_json(Explain_query *query, writer->add_member("select_id").add_ll(select_id); 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); + + if (join_tabs[i]->end_dups_weedout) + writer->end_object(); } print_explain_json_for_children(query, writer, is_analyze); 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); break; case ET_USING_WHERE: - if (where_cond) { - writer->add_member("attached_condition"); /* We are printing the condition that is checked when scanning this 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. */ 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; case ET_USING_INDEX: @@ -1110,6 +1118,15 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t break; case ET_USING_JOIN_BUFFER: /* 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; default: DBUG_ASSERT(0); diff --git a/sql/sql_explain.h b/sql/sql_explain.h index 20e2f856840..68ef59c732d 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -539,6 +539,8 @@ public: Explain_table_access() : derived_select_number(0), non_merged_sjm_number(0), + start_dups_weedout(false), + end_dups_weedout(false), where_cond(NULL), cache_cond(NULL), pushed_index_cond(NULL), @@ -615,6 +617,9 @@ public: EXPLAIN_BKA_TYPE bka_type; 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. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 511e7106bd5..985b743eaad 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23641,9 +23641,16 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab } if (tab->first_weedout_table) + { + eta->start_dups_weedout= true; eta->push_extra(ET_START_TEMPORARY); + } if (tab->check_weed_out_table) + { eta->push_extra(ET_END_TEMPORARY); + eta->end_dups_weedout= true; + } + else if (tab->do_firstmatch) { if (tab->do_firstmatch == /*join->join_tab*/ first_top_tab - 1)