diff options
author | gkodinov/kgeorge@magare.gmz <> | 2007-08-28 18:51:03 +0300 |
---|---|---|
committer | gkodinov/kgeorge@magare.gmz <> | 2007-08-28 18:51:03 +0300 |
commit | cfaa0983c841310ab75ba052579fe4727de4998a (patch) | |
tree | a6f10748580275e7b10aa99d7f88d2a5e1f10d02 | |
parent | 4446fd4b0d270aaeee8a8affa6b30ef11439431d (diff) | |
download | mariadb-git-cfaa0983c841310ab75ba052579fe4727de4998a.tar.gz |
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.
-rw-r--r-- | mysql-test/r/status.result | 48 | ||||
-rw-r--r-- | mysql-test/t/status.test | 32 | ||||
-rw-r--r-- | sql/sql_lex.h | 22 | ||||
-rw-r--r-- | sql/sql_select.cc | 8 |
4 files changed, 108 insertions, 2 deletions
diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index ca21b333a6a..36857e22aaf 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -43,3 +43,51 @@ SHOW STATUS LIKE 'max_used_connections'; Variable_name Value Max_used_connections 4 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; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 6fcb82e160d..33bba3a626a 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -139,4 +139,36 @@ disconnect con3; disconnect con2; 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 diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 94015a9fe07..ce56be79744 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1257,6 +1257,28 @@ typedef struct st_lex : public Query_tables_list void reset_n_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; struct st_lex_local: public st_lex diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b7846a7433d..7e9cb4cfbec 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4369,9 +4369,13 @@ choose_plan(JOIN *join, table_map join_tables) /* 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; DBUG_RETURN(FALSE); } |