Commit 55bfb87a authored by unknown's avatar unknown

Bug #30377: EXPLAIN loses last_query_cost when used with UNION

Currently the Last_query_cost session status variable shows
only the cost of a single flat subselect. For complex queries
(with subselects or unions etc) Last_query_cost is not valid
as it was showing the cost for the last optimized subselect.
Fixed by reseting to zero Last_query_cost when the complete
cost of the query cannot be determined.
Last_query_cost will be non-zero only for single flat queries.


mysql-test/r/status.result:
  Bug #30377: test case
mysql-test/t/status.test:
  Bug #30377: test case
sql/sql_lex.h:
  Bug #30377: helper function
sql/sql_select.cc:
  Bug #30377: don't assign cost if not on single level statement
parent b54d2011
...@@ -43,3 +43,51 @@ SHOW STATUS LIKE 'max_used_connections'; ...@@ -43,3 +43,51 @@ SHOW STATUS LIKE 'max_used_connections';
Variable_name Value Variable_name Value
Max_used_connections 4 Max_used_connections 4
SET GLOBAL thread_cache_size=@save_thread_cache_size; SET GLOBAL thread_cache_size=@save_thread_cache_size;
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1), (2);
SELECT a FROM t1 LIMIT 1;
a
1
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 2.402418
EXPLAIN SELECT a FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 2.402418
SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a;
a
1
2
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 0.000000
EXPLAIN SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
2 UNION t1 ALL NULL NULL NULL NULL 2
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL Using filesort
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 0.000000
SELECT a IN (SELECT a FROM t1) FROM t1 LIMIT 1;
a IN (SELECT a FROM t1)
1
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 0.000000
SELECT (SELECT a FROM t1 LIMIT 1) x FROM t1 LIMIT 1;
x
1
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 0.000000
SELECT * FROM t1 a, t1 b LIMIT 1;
a a
1 1
SHOW SESSION STATUS LIKE 'Last_query_cost';
Variable_name Value
Last_query_cost 4.805836
DROP TABLE t1;
...@@ -139,4 +139,36 @@ disconnect con3; ...@@ -139,4 +139,36 @@ disconnect con3;
disconnect con2; disconnect con2;
disconnect con1; disconnect con1;
#
# Bug #30377: EXPLAIN loses last_query_cost when used with UNION
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1), (2);
SELECT a FROM t1 LIMIT 1;
SHOW SESSION STATUS LIKE 'Last_query_cost';
EXPLAIN SELECT a FROM t1;
SHOW SESSION STATUS LIKE 'Last_query_cost';
SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a;
SHOW SESSION STATUS LIKE 'Last_query_cost';
EXPLAIN SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY a;
SHOW SESSION STATUS LIKE 'Last_query_cost';
SELECT a IN (SELECT a FROM t1) FROM t1 LIMIT 1;
SHOW SESSION STATUS LIKE 'Last_query_cost';
SELECT (SELECT a FROM t1 LIMIT 1) x FROM t1 LIMIT 1;
SHOW SESSION STATUS LIKE 'Last_query_cost';
SELECT * FROM t1 a, t1 b LIMIT 1;
SHOW SESSION STATUS LIKE 'Last_query_cost';
DROP TABLE t1;
# End of 5.0 tests # End of 5.0 tests
...@@ -1257,6 +1257,28 @@ typedef struct st_lex : public Query_tables_list ...@@ -1257,6 +1257,28 @@ typedef struct st_lex : public Query_tables_list
void reset_n_backup_query_tables_list(Query_tables_list *backup); void reset_n_backup_query_tables_list(Query_tables_list *backup);
void restore_backup_query_tables_list(Query_tables_list *backup); void restore_backup_query_tables_list(Query_tables_list *backup);
/**
@brief check if the statement is a single-level join
@return result of the check
@retval TRUE The statement doesn't contain subqueries, unions and
stored procedure calls.
@retval FALSE There are subqueries, UNIONs or stored procedure calls.
*/
bool is_single_level_stmt()
{
/*
This check exploits the fact that the last added to all_select_list is
on its top. So select_lex (as the first added) will be at the tail
of the list.
*/
if (&select_lex == all_selects_list && !sroutines.records)
{
DBUG_ASSERT(!all_selects_list->next_select_in_list());
return TRUE;
}
return FALSE;
}
} LEX; } LEX;
struct st_lex_local: public st_lex struct st_lex_local: public st_lex
......
...@@ -4369,9 +4369,13 @@ choose_plan(JOIN *join, table_map join_tables) ...@@ -4369,9 +4369,13 @@ choose_plan(JOIN *join, table_map join_tables)
/* /*
Store the cost of this query into a user variable Store the cost of this query into a user variable
Don't update last_query_cost for 'show status' command Don't update last_query_cost for 'show status' command.
Don't update last_query_cost for statements that are not "flat joins" :
i.e. they have subqueries, unions or call stored procedures.
TODO: calculate a correct cost for a query with subqueries and UNIONs.
*/ */
if (join->thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS) if (join->thd->lex->orig_sql_command != SQLCOM_SHOW_STATUS &&
join->thd->lex->is_single_level_stmt())
join->thd->status_var.last_query_cost= join->best_read; join->thd->status_var.last_query_cost= join->best_read;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
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