From 5ee1c25fa8043f81ad744d1c532b8c1dafa3b5ea Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Sat, 6 Dec 2014 03:11:03 +0300 Subject: [PATCH] EXPLAIN FORMAT=JSON: Full scan on NULL key (join case) --- mysql-test/r/explain_json.result | 59 ++++++++++++++++++++++++++++++++ mysql-test/t/explain_json.test | 14 ++++++++ sql/sql_explain.cc | 8 +++++ sql/sql_explain.h | 3 ++ sql/sql_select.cc | 1 + 5 files changed, 85 insertions(+) diff --git a/mysql-test/r/explain_json.result b/mysql-test/r/explain_json.result index c9b65282047..0824132de05 100644 --- a/mysql-test/r/explain_json.result +++ b/mysql-test/r/explain_json.result @@ -719,3 +719,62 @@ EXPLAIN } drop table t1; drop table t0; +# +# MDEV-7265: "Full scan on NULL key", the join case +# +CREATE TABLE t1 (a INT, KEY(a)); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (3),(4); +EXPLAIN FORMAT=JSON SELECT * FROM t1 AS outer_t1 WHERE a <> ALL ( SELECT a FROM t1, t2 WHERE b <> outer_t1.a ); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "outer_t1", + "access_type": "index", + "key": "a", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 2, + "filtered": 100, + "attached_condition": "(not((outer_t1.a,(subquery#2))))", + "using_index": true + }, + "subqueries": [ + { + "query_block": { + "select_id": 2, + "full-scan-on-null_key": { + "table": { + "table_name": "t1", + "access_type": "ref_or_null", + "possible_keys": ["a"], + "key": "a", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["func"], + "rows": 2, + "filtered": 100, + "attached_condition": "trigcond((((outer_t1.a) = t1.a) or isnull(t1.a)))", + "using_index": true + } + }, + "block-nl-join": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + }, + "buffer_type": "flat", + "join_type": "BNL", + "attached_condition": "((t2.b <> outer_t1.a) and trigcond((((outer_t1.a) = t1.a) or isnull(t1.a))))" + } + } + } + ] + } +} +DROP TABLE t1,t2; diff --git a/mysql-test/t/explain_json.test b/mysql-test/t/explain_json.test index 0ecc09691e0..476cb0d3df6 100644 --- a/mysql-test/t/explain_json.test +++ b/mysql-test/t/explain_json.test @@ -153,3 +153,17 @@ select * from t1 tbl1, t1 tbl2 where tbl2.a < tbl1.b; drop table t1; drop table t0; +--echo # +--echo # MDEV-7265: "Full scan on NULL key", the join case +--echo # + +CREATE TABLE t1 (a INT, KEY(a)); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (3),(4); + +EXPLAIN FORMAT=JSON SELECT * FROM t1 AS outer_t1 WHERE a <> ALL ( SELECT a FROM t1, t2 WHERE b <> outer_t1.a ); + +DROP TABLE t1,t2; + diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index ddd37dbbd87..800f2ce309b 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -1139,6 +1139,8 @@ void Explain_table_access::tag_to_json(Json_writer *writer, enum explain_extra_t case ET_START_TEMPORARY: case ET_END_TEMPORARY: /* Handled as "duplicates_removal: { ... } */ + case ET_FULL_SCAN_ON_NULL_KEY: + /* Handled in full_scan_on_null_key */ break; case ET_FIRST_MATCH: writer->add_member("first_match").add_str(firstmatch_table_name.c_ptr()); @@ -1188,6 +1190,9 @@ void Explain_table_access::print_explain_json(Explain_query *query, add_json_keyset(writer, "keys", &possible_keys); } + if (full_scan_on_null_key) + writer->add_member("full-scan-on-null_key").start_object(); + writer->add_member("table").start_object(); writer->add_member("table_name").add_str(table_name); @@ -1289,6 +1294,9 @@ void Explain_table_access::print_explain_json(Explain_query *query, tag_to_json(writer, extra_tags.at(i)); } + if (full_scan_on_null_key) + writer->end_object(); //"full-scan-on-null_key" + if (range_checked_fer) writer->end_object(); // "range-checked-for-each-record" diff --git a/sql/sql_explain.h b/sql/sql_explain.h index ba5a5c2e6ec..a7ef0beb649 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -562,6 +562,7 @@ public: non_merged_sjm_number(0), extra_tags(root), range_checked_fer(NULL), + full_scan_on_null_key(false), start_dups_weedout(false), end_dups_weedout(false), where_cond(NULL), @@ -634,6 +635,8 @@ public: /* Non-NULL values means this tab uses "range checked for each record" */ Explain_range_checked_fer *range_checked_fer; + + bool full_scan_on_null_key; // valid with ET_USING_JOIN_BUFFER EXPLAIN_BKA_TYPE bka_type; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c923c003fcc..a1231152254 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23687,6 +23687,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab if (tab->ref.cond_guards[part]) { eta->push_extra(ET_FULL_SCAN_ON_NULL_KEY); + eta->full_scan_on_null_key= true; break; } }