Commit 80b3f747 authored by unknown's avatar unknown

Fix bug mdev-447: Wrong output from the EXPLAIN command of the test case for lp bug #714999

The fix backports from MWL#182: Explain running statements the logic that
saves the original JOIN_TAB array of a query plan after optimization. This
array is later used during EXPLAIN to iterate over the original JOIN plan
nodes in the cases when this plan could be changed by early subquery
execution during the optimization phase of the outer query.
parent a45c451e
...@@ -4196,7 +4196,7 @@ INSERT INTO t1 VALUES (1,1),(2,1); ...@@ -4196,7 +4196,7 @@ INSERT INTO t1 VALUES (1,1),(2,1);
EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ref a a 5 const 1 Using where; Using index 1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
2 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id));
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
......
...@@ -333,7 +333,7 @@ WHERE (SELECT DISTINCT b FROM t3) > 0); ...@@ -333,7 +333,7 @@ WHERE (SELECT DISTINCT b FROM t3) > 0);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using where; Using index 1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using where; Using index
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
3 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 0 Using temporary 3 SUBQUERY t3 ALL NULL NULL NULL NULL 1 Using temporary
SELECT * SELECT *
FROM t1 FROM t1
WHERE t1.a = ( WHERE t1.a = (
...@@ -386,7 +386,7 @@ select 1 from t1 where 1 like (select 1 from t1 where 1 <=> (select 1 from t1 gr ...@@ -386,7 +386,7 @@ select 1 from t1 where 1 like (select 1 from t1 where 1 <=> (select 1 from t1 gr
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 1 1 PRIMARY t1 ALL NULL NULL NULL NULL 1
2 SUBQUERY t1 ALL NULL NULL NULL NULL 1 2 SUBQUERY t1 ALL NULL NULL NULL NULL 1
3 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 3 SUBQUERY t1 ALL NULL NULL NULL NULL 1 Using temporary; Using filesort
select 1 from t1 where 1 like (select 1 from t1 where 1 <=> (select 1 from t1 group by a1)); select 1 from t1 where 1 like (select 1 from t1 where 1 <=> (select 1 from t1 group by a1));
1 1
1 1
......
...@@ -148,7 +148,7 @@ FROM t2 GROUP BY f1 ...@@ -148,7 +148,7 @@ FROM t2 GROUP BY f1
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
2 SUBQUERY t1 system NULL NULL NULL NULL 1 2 SUBQUERY t1 system NULL NULL NULL NULL 1
3 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 3 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
drop table t1, t2, t3; drop table t1, t2, t3;
# #
# LP BUG#715034 Item_sum_distinct::clear(): Assertion `tree != 0' failed # LP BUG#715034 Item_sum_distinct::clear(): Assertion `tree != 0' failed
......
...@@ -4200,7 +4200,7 @@ INSERT INTO t1 VALUES (1,1),(2,1); ...@@ -4200,7 +4200,7 @@ INSERT INTO t1 VALUES (1,1),(2,1);
EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ref a a 5 const 1 Using where; Using index 1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
2 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id));
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
......
...@@ -4196,7 +4196,7 @@ INSERT INTO t1 VALUES (1,1),(2,1); ...@@ -4196,7 +4196,7 @@ INSERT INTO t1 VALUES (1,1),(2,1);
EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ref a a 5 const 1 Using where; Using index 1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
2 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id));
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
......
...@@ -4202,7 +4202,7 @@ INSERT INTO t1 VALUES (1,1),(2,1); ...@@ -4202,7 +4202,7 @@ INSERT INTO t1 VALUES (1,1),(2,1);
EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ref a a 5 const 1 Using where; Using index 1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
2 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id));
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
......
...@@ -4196,7 +4196,7 @@ INSERT INTO t1 VALUES (1,1),(2,1); ...@@ -4196,7 +4196,7 @@ INSERT INTO t1 VALUES (1,1),(2,1);
EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b); EXPLAIN SELECT 1 FROM t1 WHERE a = (SELECT COUNT(*) FROM t1 GROUP BY b);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ref a a 5 const 1 Using where; Using index 1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
2 SUBQUERY internal_tmp_table ALL group_key NULL NULL NULL 1 Using temporary; Using filesort 2 SUBQUERY t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id)); CREATE TABLE t1 (id int NOT NULL, st CHAR(2), INDEX idx(id));
INSERT INTO t1 VALUES INSERT INTO t1 VALUES
......
...@@ -271,8 +271,11 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field, ...@@ -271,8 +271,11 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
bool *inherited_fl); bool *inherited_fl);
JOIN_TAB *first_depth_first_tab(JOIN* join); JOIN_TAB *first_depth_first_tab(JOIN* join);
JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab); JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
JOIN_TAB *first_breadth_first_tab(JOIN *join);
JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab); enum enum_exec_or_opt {WALK_OPTIMIZATION_TABS , WALK_EXECUTION_TABS};
JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind);
JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind,
JOIN_TAB *tab);
/** /**
This handles SELECT with and without UNION. This handles SELECT with and without UNION.
...@@ -6649,12 +6652,12 @@ double JOIN::get_examined_rows() ...@@ -6649,12 +6652,12 @@ double JOIN::get_examined_rows()
{ {
ha_rows examined_rows; ha_rows examined_rows;
double prev_fanout= 1; double prev_fanout= 1;
JOIN_TAB *tab= first_breadth_first_tab(this); JOIN_TAB *tab= first_breadth_first_tab(this, WALK_OPTIMIZATION_TABS);
JOIN_TAB *prev_tab= tab; JOIN_TAB *prev_tab= tab;
examined_rows= tab->get_examined_rows(); examined_rows= tab->get_examined_rows();
while ((tab= next_breadth_first_tab(this, tab))) while ((tab= next_breadth_first_tab(this, WALK_OPTIMIZATION_TABS, tab)))
{ {
prev_fanout *= prev_tab->records_read; prev_fanout *= prev_tab->records_read;
examined_rows+= (ha_rows) (tab->get_examined_rows() * prev_fanout); examined_rows+= (ha_rows) (tab->get_examined_rows() * prev_fanout);
...@@ -7269,23 +7272,30 @@ prev_record_reads(POSITION *positions, uint idx, table_map found_ref) ...@@ -7269,23 +7272,30 @@ prev_record_reads(POSITION *positions, uint idx, table_map found_ref)
Enumerate join tabs in breadth-first fashion, including const tables. Enumerate join tabs in breadth-first fashion, including const tables.
*/ */
JOIN_TAB *first_breadth_first_tab(JOIN *join) JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind)
{ {
return join->join_tab; /* There's always one (i.e. first) table */ /* There's always one (i.e. first) table */
return (tabs_kind == WALK_EXECUTION_TABS)? join->join_tab:
join->table_access_tabs;
} }
JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab) JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind,
JOIN_TAB *tab)
{ {
JOIN_TAB* const first_top_tab= first_breadth_first_tab(join, tabs_kind);
const uint n_top_tabs_count= (tabs_kind == WALK_EXECUTION_TABS)?
join->top_join_tab_count:
join->top_table_access_tabs_count;
if (!tab->bush_root_tab) if (!tab->bush_root_tab)
{ {
/* We're at top level. Get the next top-level tab */ /* We're at top level. Get the next top-level tab */
tab++; tab++;
if (tab < join->join_tab + join->top_join_tab_count) if (tab < first_top_tab + n_top_tabs_count)
return tab; return tab;
/* No more top-level tabs. Switch to enumerating SJM nest children */ /* No more top-level tabs. Switch to enumerating SJM nest children */
tab= join->join_tab; tab= first_top_tab;
} }
else else
{ {
...@@ -7309,7 +7319,7 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab) ...@@ -7309,7 +7319,7 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, JOIN_TAB *tab)
Ok, "tab" points to a top-level table, and we need to find the next SJM Ok, "tab" points to a top-level table, and we need to find the next SJM
nest and enter it. nest and enter it.
*/ */
for (; tab < join->join_tab + join->top_join_tab_count; tab++) for (; tab < first_top_tab + n_top_tabs_count; tab++)
{ {
if (tab->bush_children) if (tab->bush_children)
return tab->bush_children->start; return tab->bush_children->start;
...@@ -7333,7 +7343,7 @@ JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const ...@@ -7333,7 +7343,7 @@ JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const
JOIN_TAB *next_top_level_tab(JOIN *join, JOIN_TAB *tab) JOIN_TAB *next_top_level_tab(JOIN *join, JOIN_TAB *tab)
{ {
tab= next_breadth_first_tab(join, tab); tab= next_breadth_first_tab(join, WALK_EXECUTION_TABS, tab);
if (tab && tab->bush_root_tab) if (tab && tab->bush_root_tab)
tab= NULL; tab= NULL;
return tab; return tab;
...@@ -7633,6 +7643,12 @@ get_best_combination(JOIN *join) ...@@ -7633,6 +7643,12 @@ get_best_combination(JOIN *join)
join->top_join_tab_count= join->join_tab_ranges.head()->end - join->top_join_tab_count= join->join_tab_ranges.head()->end -
join->join_tab_ranges.head()->start; join->join_tab_ranges.head()->start;
/*
Save pointers to select join tabs for SHOW EXPLAIN
*/
join->table_access_tabs= join->join_tab;
join->top_table_access_tabs_count= join->top_join_tab_count;
update_depend_map(join); update_depend_map(join);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -21389,8 +21405,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -21389,8 +21405,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool printing_materialize_nest= FALSE; bool printing_materialize_nest= FALSE;
uint select_id= join->select_lex->select_number; uint select_id= join->select_lex->select_number;
for (JOIN_TAB *tab= first_breadth_first_tab(join); tab; for (JOIN_TAB *tab= first_breadth_first_tab(join, WALK_OPTIMIZATION_TABS); tab;
tab= next_breadth_first_tab(join, tab)) tab= next_breadth_first_tab(join, WALK_OPTIMIZATION_TABS, tab))
{ {
if (tab->bush_root_tab) if (tab->bush_root_tab)
{ {
...@@ -21473,16 +21489,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -21473,16 +21489,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
else else
{ {
TABLE_LIST *real_table= table->pos_in_table_list; TABLE_LIST *real_table= table->pos_in_table_list;
/* item_list.push_back(new Item_string(real_table->alias,
Internal temporary tables have no corresponding table reference strlen(real_table->alias), cs));
object. Such a table may appear in EXPLAIN when a subquery that needs
a temporary table has been executed, and JOIN::exec replaced the
original JOIN with a plan to access the data in the temp table
(made by JOIN::make_simple_join).
*/
const char *tab_name= real_table ? real_table->alias :
"internal_tmp_table";
item_list.push_back(new Item_string(tab_name, strlen(tab_name), cs));
} }
/* "partitions" column */ /* "partitions" column */
if (join->thd->lex->describe & DESCRIBE_PARTITIONS) if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
......
...@@ -897,6 +897,19 @@ class JOIN :public Sql_alloc ...@@ -897,6 +897,19 @@ class JOIN :public Sql_alloc
public: public:
JOIN_TAB *join_tab, **best_ref; JOIN_TAB *join_tab, **best_ref;
/*
For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
either:
1. array of join tabs describing how to run the select, or
2. array of single join tab describing read from the temporary table.
SHOW EXPLAIN code needs to read/show #1. This is why two next members are
there for saving it.
*/
JOIN_TAB *table_access_tabs;
uint top_table_access_tabs_count;
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment