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.cc76
1 files changed, 45 insertions, 31 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 7b47bed1e09..bdf5175fc8b 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -3653,8 +3653,8 @@ bool JOIN::optimize_unflattened_subqueries()
*/
bool JOIN::choose_subquery_plan(table_map join_tables)
-{ /* The original QEP of the subquery. */
- Query_plan_state save_qep;
+{
+ Query_plan_state save_qep; /* The original QEP of the subquery. */
enum_reopt_result reopt_result= REOPT_NONE;
Item_in_subselect *in_subs;
@@ -3681,32 +3681,50 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
if (in_subs->in_strategy & SUBS_MATERIALIZATION &&
in_subs->in_strategy & SUBS_IN_TO_EXISTS)
{
- JOIN *outer_join= unit->outer_select() ? unit->outer_select()->join : NULL;
+ JOIN *outer_join;
JOIN *inner_join= this;
- /* Cost of the outer JOIN. */
- double outer_read_time, outer_record_count;
- /* Cost of the unmodified subquery. */
+ /* 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. */
double inner_read_time_1, inner_record_count_1;
- /* Cost of the subquery with injected IN-EXISTS predicates. */
- double inner_read_time_2, inner_record_count_2;
+ /* Cost and row count of the subquery with injected IN-EXISTS predicates. */
+ double inner_read_time_2;
/* The cost to compute IN via materialization. */
double materialize_strategy_cost;
/* The cost of the IN->EXISTS strategy. */
double in_exists_strategy_cost;
+ double dummy;
+ /*
+ A. Estimate the number of rows of the outer table that will be filtered
+ by the IN predicate.
+ */
+ outer_join= unit->outer_select() ? unit->outer_select()->join : NULL;
if (outer_join)
{
+ uint outer_partial_plan_len;
/*
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
- are evaluated for each complete row.
+ are evaluated for each complete row of the outer join.
*/
- uint partial_plan_len= (in_subs->get_join_tab_idx() == MAX_TABLES) ?
- outer_join->tables :
- in_subs->get_join_tab_idx() + 1;
- outer_join->get_partial_join_cost(partial_plan_len,
- &outer_read_time, &outer_record_count);
+ outer_partial_plan_len= (in_subs->get_join_tab_idx() == MAX_TABLES) ?
+ outer_join->tables :
+ in_subs->get_join_tab_idx() + 1;
+ outer_join->get_partial_join_cost(outer_partial_plan_len, &dummy,
+ &outer_record_count);
+ if (outer_join->tables > outer_join->const_tables)
+ 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;
+ }
}
else
{
@@ -3714,15 +3732,17 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
TODO: outer_join can be NULL for DELETE statements.
How to compute its cost?
*/
- outer_read_time= 1; /* TODO */
- outer_record_count= 1; /* TODO */
+ outer_record_count= 1;
+ outer_lookup_keys=1;
}
+ DBUG_ASSERT(outer_lookup_keys <= outer_record_count);
- inner_join->get_partial_join_cost(inner_join->tables,
- &inner_read_time_1,
- &inner_record_count_1);
- /* inner_read_time_1 above is a dummy, get the correct total join cost. */
+ /*
+ B. Estimate the cost and number of records of the subquery both
+ unmodified, and with injected IN->EXISTS predicates.
+ */
inner_read_time_1= inner_join->best_read;
+ inner_record_count_1= inner_join->record_count;
if (in_to_exists_where && const_tables != tables)
{
@@ -3734,9 +3754,6 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
if (reopt_result == REOPT_ERROR)
return TRUE;
- inner_join->get_partial_join_cost(inner_join->tables,
- &inner_read_time_2,
- &inner_record_count_2);
/* inner_read_time_2 above is a dummy, get the correct total join cost. */
inner_read_time_2= inner_join->best_read;
@@ -3745,13 +3762,12 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
{
/* Reoptimization would not produce any better plan. */
inner_read_time_2= inner_read_time_1;
- inner_record_count_2= inner_record_count_1;
}
- /* Compute execution costs. */
/*
- 1. Compute the cost of the materialization strategy.
+ C. Compute execution costs.
*/
+ /* C.1 Compute the cost of the materialization strategy. */
uint rowlen= get_tmp_table_rec_length(unit->first_select()->item_list);
/* The cost of writing one row into the temporary table. */
double write_cost= get_tmp_table_write_cost(thd, inner_record_count_1,
@@ -3769,12 +3785,10 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
materialize_strategy_cost= materialization_cost +
outer_record_count * lookup_cost;
- /*
- 2. Compute the cost of the IN=>EXISTS strategy.
- */
- in_exists_strategy_cost= outer_record_count * inner_read_time_2;
+ /* C.2 Compute the cost of the IN=>EXISTS strategy. */
+ in_exists_strategy_cost= outer_lookup_keys * inner_read_time_2;
- /* Compare the costs and choose the cheaper strategy. */
+ /* C.3 Compare the costs and choose the cheaper strategy. */
if (materialize_strategy_cost >= in_exists_strategy_cost)
in_subs->in_strategy&= ~SUBS_MATERIALIZATION;
else