summaryrefslogtreecommitdiff
path: root/sql/opt_subselect.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/opt_subselect.cc')
-rw-r--r--sql/opt_subselect.cc78
1 files changed, 37 insertions, 41 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 96ac9df8a6f..0d325a4b0e1 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4324,8 +4324,6 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
{
JOIN *outer_join;
JOIN *inner_join= this;
- /* Number of (partial) rows of the outer JOIN filtered by the IN predicate. */
- double outer_record_count;
/* Number of unique value combinations filtered by the IN predicate. */
double outer_lookup_keys;
/* Cost and row count of the unmodified subquery. */
@@ -4345,38 +4343,37 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
outer_join= unit->outer_select() ? unit->outer_select()->join : NULL;
if (outer_join)
{
- uint outer_partial_plan_len;
+ /*
+ The index of the last JOIN_TAB in the outer JOIN where in_subs is
+ attached (pushed to).
+ */
+ uint max_outer_join_tab_idx;
/*
Make_cond_for_table is called for predicates only in the WHERE/ON
clauses. In all other cases, predicates are not pushed to any
- JOIN_TAB, and their joi_tab_idx remains MAX_TABLES. Such predicates
+ JOIN_TAB, and their join_tab_idx remains MAX_TABLES. Such predicates
are evaluated for each complete row of the outer join.
*/
- outer_partial_plan_len= (in_subs->get_join_tab_idx() == MAX_TABLES) ?
- outer_join->table_count :
- in_subs->get_join_tab_idx() + 1;
- outer_join->get_partial_cost_and_fanout(outer_partial_plan_len,
+ DBUG_ASSERT(outer_join->table_count > 0);
+ max_outer_join_tab_idx= (in_subs->get_join_tab_idx() == MAX_TABLES) ?
+ outer_join->table_count - 1:
+ in_subs->get_join_tab_idx();
+ /*
+ TODO:
+ Currently outer_lookup_keys is computed as the number of rows in
+ the partial join including the JOIN_TAB where the IN predicate is
+ pushed to. In the general case this is a gross overestimate because
+ due to caching we are interested only in the number of unique keys.
+ The search key may be formed by columns from much fewer than all
+ tables in the partial join. Example:
+ select * from t1, t2 where t1.c1 = t2.key AND t2.c2 IN (select ...);
+ If the join order: t1, t2, the number of unique lookup keys is ~ to
+ the number of unique values t2.c2 in the partial join t1 join t2.
+ */
+ outer_join->get_partial_cost_and_fanout(max_outer_join_tab_idx,
table_map(-1),
&dummy,
- &outer_record_count);
-
- if (outer_join->table_count > outer_join->const_tables)
- {
- outer_join->get_partial_cost_and_fanout(outer_partial_plan_len,
- in_subs->used_tables(),
- &dummy,
- &outer_lookup_keys);
- /*
- outer_lookup_keys= prev_record_reads(outer_join->best_positions,
- outer_partial_plan_len,
- in_subs->used_tables());
- */
- }
- else
- {
- /* If all tables are constant, positions is undefined. */
- outer_lookup_keys= 1;
- }
+ &outer_lookup_keys);
}
else
{
@@ -4384,17 +4381,8 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
TODO: outer_join can be NULL for DELETE statements.
How to compute its cost?
*/
- outer_record_count= 1;
- outer_lookup_keys=1;
+ outer_lookup_keys= 1;
}
- /*
- There cannot be more lookup keys than the total number of records.
- TODO: this a temporary solution until we find a better way to compute
- get_partial_join_cost() and prev_record_reads() in a consitent manner,
- where it is guaranteed that (outer_lookup_keys <= outer_record_count).
- */
- if (outer_lookup_keys > outer_record_count)
- outer_lookup_keys= outer_record_count;
/*
B. Estimate the cost and number of records of the subquery both
@@ -4442,7 +4430,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
write_cost * inner_record_count_1;
materialize_strategy_cost= materialization_cost +
- outer_record_count * lookup_cost;
+ outer_lookup_keys * lookup_cost;
/* C.2 Compute the cost of the IN=>EXISTS strategy. */
in_exists_strategy_cost= outer_lookup_keys * inner_read_time_2;
@@ -4452,6 +4440,14 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
in_subs->in_strategy&= ~SUBS_MATERIALIZATION;
else
in_subs->in_strategy&= ~SUBS_IN_TO_EXISTS;
+
+ DBUG_PRINT("info",
+ ("mat_strategy_cost: %.2f, mat_cost: %.2f, write_cost: %.2f, lookup_cost: %.2f",
+ materialize_strategy_cost, materialization_cost, write_cost, lookup_cost));
+ DBUG_PRINT("info",
+ ("inx_strategy_cost: %.2f, inner_read_time_2: %.2f",
+ in_exists_strategy_cost, inner_read_time_2));
+ DBUG_PRINT("info",("outer_lookup_keys: %.2f", outer_lookup_keys));
}
/*
@@ -4507,9 +4503,9 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
const_tables != table_count)
{
/*
- The subquery was not reoptimized either because the user allowed only the
- IN-EXISTS strategy, or because materialization was not possible based on
- semantic analysis. Clenup the original plan and reoptimize.
+ The subquery was not reoptimized either because the user allowed only
+ the IN-EXISTS strategy, or because materialization was not possible
+ based on semantic analysis. Cleanup the original plan and reoptimize.
*/
for (uint i= 0; i < table_count; i++)
{