summaryrefslogtreecommitdiff
path: root/sql/opt_subselect.cc
diff options
context:
space:
mode:
authorunknown <timour@askmonty.org>2012-05-17 13:46:05 +0300
committerunknown <timour@askmonty.org>2012-05-17 13:46:05 +0300
commitda5214831d3d0f0880b4068a06ce062ca703293f (patch)
tree68eb72f263dbf5719ba926505b3cfbbd8afd52c9 /sql/opt_subselect.cc
parentddd3e261b253856720bd9dc2343a655ecc297e81 (diff)
downloadmariadb-git-da5214831d3d0f0880b4068a06ce062ca703293f.tar.gz
Fix for bug lp:944706, task MDEV-193
The patch enables back constant subquery execution during query optimization after it was disabled during the development of MWL#89 (cost-based choice of IN-TO-EXISTS vs MATERIALIZATION). The main idea is that constant subqueries are allowed to be executed during optimization if their execution is not expensive. The approach is as follows: - Constant subqueries are recursively optimized in the beginning of JOIN::optimize of the outer query. This is done by the new method JOIN::optimize_constant_subqueries(). This is done so that the cost of executing these queries can be estimated. - Optimization of the outer query proceeds normally. During this phase the optimizer may request execution of non-expensive constant subqueries. Each place where the optimizer may potentially execute an expensive expression is guarded with the predicate Item::is_expensive(). - The implementation of Item_subselect::is_expensive has been extended to use the number of examined rows (estimated by the optimizer) as a way to determine whether the subquery is expensive or not. - The new system variable "expensive_subquery_limit" controls how many examined rows are considered to be not expensive. The default is 100. In addition, multiple changes were needed to make this solution work in the light of the changes made by MWL#89. These changes were needed to fix various crashes and wrong results, and legacy bugs discovered during development.
Diffstat (limited to 'sql/opt_subselect.cc')
-rw-r--r--sql/opt_subselect.cc47
1 files changed, 45 insertions, 2 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 9bf1aaf4039..3e21187e6fa 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4872,7 +4872,43 @@ static void remove_subq_pushed_predicates(JOIN *join, Item **where)
bool JOIN::optimize_unflattened_subqueries()
{
- return select_lex->optimize_unflattened_subqueries();
+ return select_lex->optimize_unflattened_subqueries(false);
+}
+
+/**
+ Optimize all constant subqueries of a query that were not flattened into
+ a semijoin.
+
+ @details
+ Similar to other constant conditions, constant subqueries can be used in
+ various constant optimizations. Having optimized constant subqueries before
+ these constant optimizations, makes it possible to estimate if a subquery
+ is "cheap" enough to be executed during the optimization phase.
+
+ Constant subqueries can be optimized and evaluated independent of the outer
+ query, therefore if const_only = true, this method can be called early in
+ the optimization phase of the outer query.
+
+ @return Operation status
+ @retval FALSE success.
+ @retval TRUE error occurred.
+*/
+
+bool JOIN::optimize_constant_subqueries()
+{
+ ulonglong save_options= select_lex->options;
+ bool res;
+ /*
+ Constant subqueries may be executed during the optimization phase.
+ In EXPLAIN mode the optimizer doesn't initialize many of the data structures
+ needed for execution. In order to make it possible to execute subqueries
+ during optimization, constant subqueries must be optimized for execution,
+ not for EXPLAIN.
+ */
+ select_lex->options&= ~SELECT_DESCRIBE;
+ res= select_lex->optimize_unflattened_subqueries(true);
+ select_lex->options= save_options;
+ return res;
}
@@ -5273,7 +5309,14 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
by the IN predicate.
*/
outer_join= unit->outer_select() ? unit->outer_select()->join : NULL;
- if (outer_join && outer_join->table_count > 0)
+ /*
+ Get the cost of the outer join if:
+ (1) It has at least one table, and
+ (2) It has been already optimized (if there is no join_tab, then the
+ outer join has not been optimized yet).
+ */
+ if (outer_join && outer_join->table_count > 0 && // (1)
+ outer_join->join_tab) // (2)
{
/*
TODO: