summaryrefslogtreecommitdiff
path: root/sql/opt_range.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r--sql/opt_range.cc234
1 files changed, 134 insertions, 100 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 00b83f3759c..ba2497c48a8 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -412,7 +412,6 @@ static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
static bool null_part_in_key(KEY_PART *key_part, const uchar *key,
uint length);
-static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static
SEL_ARG *enforce_sel_arg_weight_limit(RANGE_OPT_PARAM *param, uint keyno,
@@ -2325,6 +2324,7 @@ public:
struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */
bool is_covering; /* TRUE if no row retrieval phase is necessary */
double index_scan_costs; /* SUM(cost(index_scan)) */
+ double cmp_cost; // Cost of out rows with WHERE clause
void trace_basic_info(PARAM *param,
Json_writer_object *trace_object) const;
};
@@ -2684,7 +2684,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
bool only_single_index_range_scan)
{
uint idx;
- double scan_time;
Item *notnull_cond= NULL;
TABLE_READ_PLAN *best_trp= NULL;
SEL_ARG **backup_keys= 0;
@@ -2712,20 +2711,23 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
only_single_index_range_scan= 1;
if (head->force_index || force_quick_range)
- scan_time= read_time= DBL_MAX;
+ read_time= DBL_MAX;
else
{
- scan_time= rows2double(records) / TIME_FOR_COMPARE;
+ read_time= head->file->ha_scan_and_compare_time(records);
+
/*
- The 2 is there to prefer range scans to full table scans.
- This is mainly to make the test suite happy as many tests has
- very few rows. In real life tables has more than a few rows and the
- +2 has no practical effect.
+ Force the detection of range access if LIMIT is used.
+ The idea is that we want to store all possible range
+ accesses to see if we can use them to resolve an ORDER BY.
+ Ranges with too high costs will be pruned in best_access_path().
+
+ The test for read_time is there only to not modify read_time if
+ ha_scan_and_compare_time() returned a really big value
*/
- read_time= (double) head->file->scan_time() + scan_time + 2;
- if (limit < records && read_time < (double) records + scan_time + 1 )
+ if (limit < records && read_time < (double) records * 2)
{
- read_time= (double) records + scan_time + 1; // Force to use index
+ read_time= (double) records * 2; // Force to use index
notnull_cond= NULL;
}
}
@@ -2868,8 +2870,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (!force_quick_range && !head->covering_keys.is_clear_all())
{
int key_for_use= find_shortest_key(head, &head->covering_keys);
- double key_read_time= (head->file->key_scan_time(key_for_use) +
- rows2double(records) / TIME_FOR_COMPARE);
+ double key_read_time;
+ key_read_time= head->file->ha_key_scan_and_compare_time(key_for_use,
+ records);
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
"read time %g", key_for_use, key_read_time));
@@ -2977,8 +2980,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if ((rori_trp= get_best_ror_intersect(&param, tree, best_read_time,
&can_build_covering)))
{
- best_trp= rori_trp;
- best_read_time= best_trp->read_cost;
+ best_trp= rori_trp;
+ best_read_time= rori_trp->read_cost;
/*
Try constructing covering ROR-intersect only if it looks possible
and worth doing.
@@ -3002,10 +3005,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if ((intersect_trp= get_best_index_intersect(&param, tree,
best_read_time)))
{
- best_trp= intersect_trp;
- best_read_time= best_trp->read_cost;
- set_if_smaller(param.table->opt_range_condition_rows,
- intersect_trp->records);
+ best_trp= intersect_trp;
+ best_read_time= intersect_trp->read_cost;
+ param.table->set_opt_range_condition_rows(intersect_trp->records);
}
}
@@ -3024,8 +3026,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
{
new_conj_trp= get_best_disjunct_quick(&param, imerge, best_read_time);
if (new_conj_trp)
- set_if_smaller(param.table->opt_range_condition_rows,
- new_conj_trp->records);
+ param.table->set_opt_range_condition_rows(new_conj_trp->records);
if (new_conj_trp &&
(!best_conj_trp ||
new_conj_trp->read_cost < best_conj_trp->read_cost))
@@ -3053,7 +3054,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
{
/* mark that we are changing opt_range_condition_rows */
group_by_optimization_used= 1;
- set_if_smaller(param.table->opt_range_condition_rows, group_trp->records);
+ param.table->set_opt_range_condition_rows(group_trp->records);
DBUG_PRINT("info", ("table_rows: %llu opt_range_condition_rows: %llu "
"group_trp->records: %ull",
table_records, param.table->opt_range_condition_rows,
@@ -3409,7 +3410,11 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
}
if (!*cond || table->pos_in_table_list->schema_table)
+ {
+ table->set_cond_selectivity(table->opt_range_condition_rows /
+ table_records);
DBUG_RETURN(FALSE);
+ }
/*
This should be pre-alloced so that we could use the same bitmap for all
@@ -3556,12 +3561,6 @@ end_of_range_loop:
table_records);
if (original_selectivity < table->cond_selectivity)
{
- DBUG_ASSERT(quick &&
- (quick->group_by_optimization_used ||
- quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
- quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
- quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
- quick->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT));
table->cond_selectivity= original_selectivity;
if (unlikely(thd->trace_started()))
{
@@ -5068,17 +5067,26 @@ static void dbug_print_singlepoint_range(SEL_ARG **start, uint num)
Get cost of 'sweep' full records retrieval.
SYNOPSIS
get_sweep_read_cost()
- param Parameter from test_quick_select
- records # of records to be retrieved
+ param Parameter from test_quick_select
+ records # of records to be retrieved
+ add_time_for_compare If set, add cost of WHERE clause (TIME_FOR_COMPARE)
RETURN
cost of sweep
*/
-double get_sweep_read_cost(const PARAM *param, ha_rows records)
+static double get_sweep_read_cost(const PARAM *param, ha_rows records,
+ bool add_time_for_compare)
{
+ DBUG_ENTER("get_sweep_read_cost");
+#ifndef OLD_SWEEP_COST
+ double cost= (param->table->file->ha_rnd_pos_time(records) +
+ (add_time_for_compare ? records / TIME_FOR_COMPARE : 0));
+ DBUG_PRINT("return", ("cost: %g", cost));
+ DBUG_RETURN(cost);
+#else
double result;
uint pk= param->table->s->primary_key;
- DBUG_ENTER("get_sweep_read_cost");
+
if (param->table->file->pk_is_clustering_key(pk) ||
param->table->file->stats.block_size == 0 /* HEAP */)
{
@@ -5086,12 +5094,12 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
We are using the primary key to find the rows.
Calculate the cost for this.
*/
- result= param->table->file->read_time(pk, (uint)records, records);
+ result= table->file->ha_rnd_pos_time(records);
}
else
{
/*
- Rows will be retreived with rnd_pos(). Caluclate the expected
+ Rows will be retreived with rnd_pos(). Calculate the expected
cost for this.
*/
double n_blocks=
@@ -5124,9 +5132,11 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
*/
result= busy_blocks;
}
+ result+= rows2double(n_rows) * ROW_COPY_COST;
}
DBUG_PRINT("return",("cost: %g", result));
DBUG_RETURN(result);
+#endif /* OLD_SWEEP_COST */
}
@@ -5280,7 +5290,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
imerge_cost += (*cur_child)->read_cost;
all_scans_ror_able &= ((*ptree)->n_ror_scans > 0);
all_scans_rors &= (*cur_child)->is_ror;
- if (param->table->file->is_clustering_key(param->real_keynr[(*cur_child)->key_idx]))
+ if (param->table->file->is_clustering_key(keynr_in_table))
{
cpk_scan= cur_child;
cpk_scan_records= (*cur_child)->records;
@@ -5344,7 +5354,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
/* Calculate cost(rowid_to_row_scan) */
{
- double sweep_cost= get_sweep_read_cost(param, non_cpk_scan_records);
+ /* imerge_cost already includes TIME_FOR_COMPARE */
+ double sweep_cost= get_sweep_read_cost(param, non_cpk_scan_records, 0);
imerge_cost+= sweep_cost;
trace_best_disjunct.
add("records", non_cpk_scan_records).
@@ -5453,29 +5464,27 @@ skip_to_ror_scan:
{
/* Ok, we have index_only cost, now get full rows scan cost */
cost= param->table->file->
- read_time(param->real_keynr[(*cur_child)->key_idx], 1,
- (*cur_child)->records) +
- rows2double((*cur_child)->records) / TIME_FOR_COMPARE;
+ ha_read_and_compare_time(param->real_keynr[(*cur_child)->key_idx], 1,
+ (*cur_child)->records);
}
else
cost= read_time;
TABLE_READ_PLAN *prev_plan= *cur_child;
- if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost,
- &dummy)))
+ TRP_ROR_INTERSECT *ror_trp;
+ if (!(*cur_roru_plan= ror_trp= get_best_ror_intersect(param, *ptree, cost,
+ &dummy)))
{
- if (prev_plan->is_ror)
- *cur_roru_plan= prev_plan;
- else
+ if (!prev_plan->is_ror)
DBUG_RETURN(imerge_trp);
+ *cur_roru_plan= prev_plan;
roru_index_costs += (*cur_roru_plan)->read_cost;
}
else
- roru_index_costs +=
- ((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
+ roru_index_costs += ror_trp->index_scan_costs;
roru_total_records += (*cur_roru_plan)->records;
- roru_intersect_part *= (*cur_roru_plan)->records /
- param->table->stat_records();
+ roru_intersect_part *= ((*cur_roru_plan)->records /
+ param->table->stat_records());
}
trace_analyze_ror.end();
/*
@@ -5496,10 +5505,10 @@ skip_to_ror_scan:
*/
double roru_total_cost;
- roru_total_cost= roru_index_costs +
- rows2double(roru_total_records)*log((double)n_child_scans) /
- (TIME_FOR_COMPARE_ROWID * M_LN2) +
- get_sweep_read_cost(param, roru_total_records);
+ roru_total_cost= (roru_index_costs +
+ rows2double(roru_total_records)*log((double)n_child_scans) /
+ (TIME_FOR_COMPARE_ROWID * M_LN2) +
+ get_sweep_read_cost(param, roru_total_records, 0));
DBUG_PRINT("info", ("ROR-union: cost %g, %zu members",
roru_total_cost, n_child_scans));
@@ -5532,7 +5541,7 @@ skip_to_ror_scan:
SYNOPSIS
merge_same_index_scans()
param Context info for the operation
- imerge IN/OUT SEL_IMERGE from which imerge_trp has been extracted
+ imerge IN/OUT SEL_IMERGE from which imerge_trp has been extracted
imerge_trp The index merge plan where index scans for the same
indexes are to be merges
read_time The upper bound for the cost of the plan to be evaluated
@@ -5925,11 +5934,11 @@ bool prepare_search_best_index_intersect(PARAM *param,
continue;
}
- cost= table->opt_range[(*index_scan)->keynr].index_only_cost;
+ cost= table->opt_range[(*index_scan)->keynr].index_only_fetch_cost();
idx_scan.add("cost", cost);
- if (cost >= cutoff_cost)
+ if (cost + COST_EPS >= cutoff_cost)
{
if (unlikely(idx_scan.trace_started()))
idx_scan.add("chosen", false).add("cause", "cost");
@@ -5987,7 +5996,7 @@ bool prepare_search_best_index_intersect(PARAM *param,
return TRUE;
common->best_uses_cpk= FALSE;
- common->best_cost= cutoff_cost + COST_EPS;
+ common->best_cost= cutoff_cost;
common->best_length= 0;
if (!(common->best_intersect=
@@ -6409,7 +6418,7 @@ bool check_index_intersect_extension(PARTIAL_INDEX_INTERSECT_INFO *curr,
if (cost >= cutoff_cost)
return FALSE;
- cost+= get_sweep_read_cost(common_info->param, records);
+ cost+= get_sweep_read_cost(common_info->param, records, 1);
next->cost= cost;
next->length= curr->length+1;
@@ -6510,7 +6519,6 @@ TRP_INDEX_INTERSECT *get_best_index_intersect(PARAM *param, SEL_TREE *tree,
TRP_INDEX_INTERSECT *intersect_trp= NULL;
TABLE *table= param->table;
THD *thd= param->thd;
-
DBUG_ENTER("get_best_index_intersect");
Json_writer_object trace_idx_interect(thd, "analyzing_sort_intersect");
@@ -6578,7 +6586,7 @@ TRP_INDEX_INTERSECT *get_best_index_intersect(PARAM *param, SEL_TREE *tree,
{
intersect_trp->read_cost= common.best_cost;
- intersect_trp->records= common.best_records;
+ intersect_trp->records= common.best_records;
intersect_trp->range_scans= range_scans;
intersect_trp->range_scans_end= cur_range;
intersect_trp->filtered_scans= common.filtered_scans;
@@ -6687,7 +6695,8 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg)
ror queue.
*/
ror_scan->index_read_cost=
- param->table->file->keyread_time(ror_scan->keynr, 1, ror_scan->records);
+ param->table->file->ha_keyread_and_copy_time(ror_scan->keynr, 1,
+ ror_scan->records);
DBUG_RETURN(ror_scan);
}
@@ -7048,8 +7057,8 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
each record of every scan. Assuming 1/TIME_FOR_COMPARE_ROWID
per check this gives us:
*/
- const double idx_cost= rows2double(info->index_records) /
- TIME_FOR_COMPARE_ROWID;
+ const double idx_cost= (rows2double(info->index_records) /
+ TIME_FOR_COMPARE_ROWID);
info->index_scan_costs+= idx_cost;
trace_costs->add("index_scan_cost", idx_cost);
}
@@ -7073,13 +7082,15 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info,
if (!info->is_covering)
{
double sweep_cost= get_sweep_read_cost(info->param,
- double2rows(info->out_rows));
+ double2rows(info->out_rows), 1);
info->total_cost+= sweep_cost;
trace_costs->add("disk_sweep_cost", sweep_cost);
DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost));
}
else
- trace_costs->add("disk_sweep_cost", 0);
+ {
+ trace_costs->add("disk_sweep_cost", static_cast<longlong>(0));
+ }
DBUG_PRINT("info", ("New out_rows: %g", info->out_rows));
DBUG_PRINT("info", ("New cost: %g, %scovering", info->total_cost,
@@ -7158,7 +7169,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
bool *are_all_covering)
{
uint idx;
- double min_cost= DBL_MAX;
+ double min_cost= DBL_MAX, cmp_cost;
THD *thd= param->thd;
DBUG_ENTER("get_best_ror_intersect");
DBUG_PRINT("enter", ("opt_range_condition_rows: %llu cond_selectivity: %g",
@@ -7274,12 +7285,18 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
*(intersect_scans_end++)= *(cur_ror_scan++);
+ /*
+ Check if intersect gives a lower cost.
+ The first ror scan is always accepted.
+ The next ror scan is only accepted if the total cost went down
+ (Enough rows where reject to offset the intersect cost)
+ */
if (intersect->total_cost < min_cost)
{
/* Local minimum found, save it */
+ min_cost= intersect->total_cost;
ror_intersect_cpy(intersect_best, intersect);
intersect_scans_best= intersect_scans_end;
- min_cost = intersect->total_cost;
trace_idx.add("chosen", true);
}
else
@@ -7320,10 +7337,11 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
if (ror_intersect_add(intersect, cpk_scan, &trace_cpk, TRUE) &&
(intersect->total_cost < min_cost))
{
+ min_cost= intersect->total_cost;
if (trace_cpk.trace_started())
- trace_cpk.
- add("clustered_pk_scan_added_to_intersect", true).
- add("cumulated_cost", intersect->total_cost);
+ trace_cpk.
+ add("clustered_pk_scan_added_to_intersect", true).
+ add("cumulated_cost", intersect->total_cost);
intersect_best= intersect; //just set pointer here
}
else
@@ -7345,12 +7363,20 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
}
trace_cpk.end();
+ /*
+ Adjust row count and add the cost of comparing the final rows to the
+ WHERE clause
+ */
+ cmp_cost= intersect_best->out_rows/TIME_FOR_COMPARE;
+
/* Ok, return ROR-intersect plan if we have found one */
TRP_ROR_INTERSECT *trp= NULL;
- if (min_cost < read_time && (cpk_scan || best_num > 1))
+ if (min_cost + cmp_cost < read_time && (cpk_scan || best_num > 1))
{
+ double best_rows= double2rows(intersect_best->out_rows);
+ set_if_bigger(best_rows, 1);
if (!(trp= new (param->mem_root) TRP_ROR_INTERSECT))
- DBUG_RETURN(trp);
+ DBUG_RETURN(NULL);
if (!(trp->first_scan=
(ROR_SCAN_INFO**)alloc_root(param->mem_root,
sizeof(ROR_SCAN_INFO*)*best_num)))
@@ -7358,12 +7384,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
memcpy(trp->first_scan, intersect_scans, best_num*sizeof(ROR_SCAN_INFO*));
trp->last_scan= trp->first_scan + best_num;
trp->is_covering= intersect_best->is_covering;
- trp->read_cost= intersect_best->total_cost;
- /* Prevent divisons by zero */
- ha_rows best_rows = double2rows(intersect_best->out_rows);
- if (!best_rows)
- best_rows= 1;
- set_if_smaller(param->table->opt_range_condition_rows, best_rows);
+ trp->read_cost= min_cost + cmp_cost;
+ param->table->set_opt_range_condition_rows(best_rows);
trp->records= best_rows;
trp->index_scan_costs= intersect_best->index_scan_costs;
trp->cpk_scan= cpk_scan;
@@ -7381,12 +7403,11 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree,
{
trace_ror.
add("chosen", false).
- add("cause", (read_time >= min_cost)
- ? "too few indexes to merge"
- : "cost");
+ add("cause", (min_cost + cmp_cost >= read_time) ?
+ "cost" : "too few indexes to merge");
}
- DBUG_PRINT("enter", ("opt_range_condition_rows: %llu",
- (ulonglong) param->table->opt_range_condition_rows));
+ DBUG_PRINT("exit", ("opt_range_condition_rows: %llu",
+ (ulonglong) param->table->opt_range_condition_rows));
DBUG_RETURN(trp);
}
@@ -7458,7 +7479,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
DBUG_RETURN(0);
bitmap_clear_all(covered_fields);
- double total_cost= 0.0f;
+ double total_cost= 0.0;
ha_rows records=0;
bool all_covered;
@@ -7520,6 +7541,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
(TIME_FOR_COMPARE_ROWID * M_LN2);
DBUG_PRINT("info", ("Covering ROR-intersect full cost: %g", total_cost));
+ /* TODO: Add TIME_FOR_COMPARE cost to total_cost */
+
if (total_cost > read_time)
DBUG_RETURN(NULL);
@@ -7537,9 +7560,9 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
trp->read_cost= total_cost;
trp->records= records;
trp->cpk_scan= NULL;
- set_if_smaller(param->table->opt_range_condition_rows, records);
+ param->table->set_opt_range_condition_rows(records);
- DBUG_PRINT("info",
+ DBUG_PRINT("exit",
("Returning covering ROR-intersect plan: cost %g, records %lu",
trp->read_cost, (ulong) trp->records));
DBUG_RETURN(trp);
@@ -7622,19 +7645,19 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
for_range_access, &mrr_flags,
&buf_size, &cost, &is_ror_scan);
- if (!for_range_access && !is_ror_scan &&
- !optimizer_flag(param->thd,OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION))
+ if (found_records == HA_POS_ERROR ||
+ (!for_range_access && !is_ror_scan &&
+ !optimizer_flag(param->thd,OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION)))
{
/* The scan is not a ROR-scan, just skip it */
continue;
}
-
- if (found_records != HA_POS_ERROR && tree->index_scans &&
+ found_read_time= cost.total_cost();
+ if (tree->index_scans &&
(index_scan= (INDEX_SCAN_INFO *)alloc_root(param->mem_root,
sizeof(INDEX_SCAN_INFO))))
{
Json_writer_array trace_range(thd, "ranges");
-
const KEY &cur_key= param->table->key_info[keynr];
const KEY_PART_INFO *key_part= cur_key.key_part;
@@ -7657,15 +7680,14 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
add("using_mrr", !(mrr_flags & HA_MRR_USE_DEFAULT_IMPL)).
add("index_only", read_index_only).
add("rows", found_records).
- add("cost", cost.total_cost());
+ add("cost", found_read_time);
}
- if ((found_records != HA_POS_ERROR) && is_ror_scan)
+ if (is_ror_scan)
{
tree->n_ror_scans++;
tree->ror_scans_map.set_bit(idx);
}
- if (found_records != HA_POS_ERROR &&
- read_time > (found_read_time= cost.total_cost()))
+ if (read_time > found_read_time)
{
read_time= found_read_time;
best_records= found_records;
@@ -11761,16 +11783,28 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
param->table->opt_range_keys.set_bit(keynr);
range->key_parts= param->max_key_parts;
range->ranges= param->range_count;
- param->table->opt_range_condition_rows=
- MY_MIN(param->table->opt_range_condition_rows, rows);
+ param->table->set_opt_range_condition_rows(rows);
+ range->selectivity= (rows ?
+ (param->table->opt_range_condition_rows /
+ rows) :
+ 1.0); // ok as rows is 0
range->rows= rows;
- range->fetch_cost= cost->fetch_cost();
- /* Same as total cost */
- range->cost= range->fetch_cost + cost->compare_cost();
+ /* cost of finding a row without copy or checking the where */
+ range->find_cost= cost->find_cost();
+ /* cost of finding a row copying it to the row buffer */
+ range->fetch_cost= range->find_cost + cost->data_copy_cost();
+ /* Add comparing it to the where. Same as cost.total_cost() */
+ range->cost= (range->fetch_cost + cost->compare_cost());
+ /* Calculate the cost of just finding the key. Used by filtering */
if (param->table->file->is_clustering_key(keynr))
- range->index_only_cost= 0;
+ range->index_only_cost= range->find_cost;
else
+ {
range->index_only_cost= cost->index_only_cost();
+ DBUG_ASSERT(!(*mrr_flags & HA_MRR_INDEX_ONLY) ||
+ range->index_only_cost ==
+ range->find_cost);
+ }
range->first_key_part_has_only_one_value=
check_if_first_key_part_has_only_one_value(tree);
}