From a80a797686e72644e0ad479fdfd2a3b56c4ddf05 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sat, 6 Dec 2014 02:23:37 +0300 Subject: [PATCH] EXPLAIN FORMAT=JSON: Support "range checked for each record" --- mysql-test/r/explain_json.result | 26 ++++++++++++++++++++ mysql-test/t/explain_json.test | 5 ++++ sql/sql_explain.cc | 42 +++++++++++++++++++++++--------- sql/sql_explain.h | 19 ++++++++++++--- sql/sql_select.cc | 5 +++- 5 files changed, 82 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/explain_json.result b/mysql-test/r/explain_json.result index 42c273e7209..c9b65282047 100644 --- a/mysql-test/r/explain_json.result +++ b/mysql-test/r/explain_json.result @@ -691,5 +691,31 @@ EXPLAIN } } } +# 'Range checked for each record' +set optimizer_switch=@tmp; +explain format=json +select * from t1 tbl1, t1 tbl2 where tbl2.a < tbl1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "tbl1", + "access_type": "ALL", + "rows": 100, + "filtered": 100 + }, + "range-checked-for-each-record": { + "keys": ["a"], + "table": { + "table_name": "tbl2", + "access_type": "ALL", + "possible_keys": ["a"], + "rows": 100, + "filtered": 100 + } + } + } +} drop table t1; drop table t0; diff --git a/mysql-test/t/explain_json.test b/mysql-test/t/explain_json.test index 5b6a0e135eb..0ecc09691e0 100644 --- a/mysql-test/t/explain_json.test +++ b/mysql-test/t/explain_json.test @@ -145,6 +145,11 @@ set optimizer_switch='mrr=on,mrr_sort_keys=on'; explain format=json select * from t1 where a < 3; +--echo # 'Range checked for each record' +set optimizer_switch=@tmp; +explain format=json +select * from t1 tbl1, t1 tbl2 where tbl2.a < tbl1.b; + drop table t1; drop table t0; diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index f2be3777da8..ddd37dbbd87 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -1132,6 +1132,8 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t case ET_USING: // index merge: case ET_USING break; + case ET_RANGE_CHECKED_FOR_EACH_RECORD: + /* Handled as range_checked_fer */ case ET_USING_JOIN_BUFFER: /* Do nothing. Join buffer is handled differently */ case ET_START_TEMPORARY: @@ -1153,6 +1155,22 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t } +static +void add_json_keyset(Json_writer *writer, const char *elem_name, + String_list *keyset) +{ + if (!keyset->is_empty()) + { + List_iterator_fast it(*keyset); + const char *name; + writer->add_member(elem_name).start_array(); + while ((name= it++)) + writer->add_str(name); + writer->end_array(); + } +} + + void Explain_table_access::print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze) @@ -1164,20 +1182,19 @@ void Explain_table_access::print_explain_json(Explain_query *query, writer->add_member("block-nl-join").start_object(); } + if (range_checked_fer) + { + writer->add_member("range-checked-for-each-record").start_object(); + add_json_keyset(writer, "keys", &possible_keys); + } + writer->add_member("table").start_object(); writer->add_member("table_name").add_str(table_name); // partitions writer->add_member("access_type").add_str(join_type_str[type]); - if (!possible_keys.is_empty()) - { - List_iterator_fast it(possible_keys); - const char *name; - writer->add_member("possible_keys").start_array(); - while ((name= it++)) - writer->add_str(name); - writer->end_array(); - } + + add_json_keyset(writer, "possible_keys", &possible_keys); /* `key` */ /* For non-basic quick select, 'key' will not be present */ @@ -1271,10 +1288,13 @@ void Explain_table_access::print_explain_json(Explain_query *query, { tag_to_json(writer, extra_tags.at(i)); } + + if (range_checked_fer) + writer->end_object(); // "range-checked-for-each-record" if (bka_type.is_using_jbuf()) { - writer->end_object(); + writer->end_object(); // "block-nl-join" writer->add_member("buffer_type").add_str(bka_type.incremental? "incremental":"flat"); writer->add_member("join_type").add_str(bka_type.join_alg); @@ -1388,7 +1408,7 @@ void Explain_table_access::append_tag_name(String *str, enum explain_extra_tag t char buf[MAX_KEY / 4 + 1]; str->append(STRING_WITH_LEN("Range checked for each " "record (index map: 0x")); - str->append(range_checked_map.print(buf)); + str->append(range_checked_fer->keys_map.print(buf)); str->append(')'); break; } diff --git a/sql/sql_explain.h b/sql/sql_explain.h index 5e96cd78657..ba5a5c2e6ec 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -538,6 +538,18 @@ private: }; +/* + Data structure for "range checked for each record". + It's a set of keys, tabular explain prints hex bitmap, json prints key names. +*/ + +class Explain_range_checked_fer : public Sql_alloc +{ +public: + String_list key_set; + key_map keys_map; +}; + /* EXPLAIN data structure for a single JOIN_TAB. */ @@ -549,6 +561,7 @@ public: derived_select_number(0), non_merged_sjm_number(0), extra_tags(root), + range_checked_fer(NULL), start_dups_weedout(false), end_dups_weedout(false), where_cond(NULL), @@ -618,9 +631,9 @@ public: // Valid if ET_USING tag is present Explain_quick_select *quick_info; - - // valid with ET_RANGE_CHECKED_FOR_EACH_RECORD - key_map range_checked_map; + + /* Non-NULL values means this tab uses "range checked for each record" */ + Explain_range_checked_fer *range_checked_fer; // valid with ET_USING_JOIN_BUFFER EXPLAIN_BKA_TYPE bka_type; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 354b7620888..c923c003fcc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23574,7 +23574,10 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab if (tab->use_quick == 2) { eta->push_extra(ET_RANGE_CHECKED_FOR_EACH_RECORD); - eta->range_checked_map= tab->keys; + eta->range_checked_fer= new (thd->mem_root) Explain_range_checked_fer; + eta->range_checked_fer->keys_map= tab->keys; + append_possible_keys(thd->mem_root, eta->range_checked_fer->key_set, + table, tab->keys); } else if (tab->select->cond || (tab->cache_select && tab->cache_select->cond))