Commit 2387ee9b authored by Monty's avatar Monty Committed by Sergei Petrunia

Added 'records_out' and join_type to POSITION

records_out is the numbers of rows expected to be accepted from a table.
records_read is in contrast the number of rows that the optimizer excepts
to read from the engine.

This patch causes not plan changes. The differences in test results comes
from renaming "records" to "records_read" and printing of record_out in
the optimizer trace.

Other things:
- Renamed table_cond_selectivity() to table_after_join_selectivity()
  to make the purpose of the function more clear.
parent 9db877c9
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -928,3 +928,37 @@ set optimizer_trace='enabled=off'; ...@@ -928,3 +928,37 @@ set optimizer_trace='enabled=off';
--echo # End of 10.6 tests --echo # End of 10.6 tests
--echo #
--echo # Testing of records_out
--echo #
set @save_optimizer_switch= @@optimizer_switch;
set @save_use_stat_tables= @@use_stat_tables;
set @save_histogram_size= @@histogram_size;
set @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
set optimizer_switch='rowid_filter=on';
set use_stat_tables='preferably';
set optimizer_use_condition_selectivity=4;
set histogram_size=127;
create table t1 (a int, b int, c int, key(a),key(b));
insert into t1 select seq, seq*2, seq/10 from seq_1_to_1000;
analyze table t1;
--optimizer_trace
explain select * from t1 where a<10 and b between 10 and 50 and c < 10;
drop table t1;
create table three (a int);
insert into three values (1),(2),(3);
create table t1 (a int, b int, c int, key(a),key(b));
insert into t1 select mod(seq,10), seq, seq from seq_1_to_10000;
analyze table t1;
--optimizer_trace
explain format=json select * from three, t1 where t1.a=three.a and t1.b<5000 and t1.c<1000;
drop table three, t1;
set @@optimizer_switch= @save_optimizer_switch;
set @@use_stat_tables= @save_use_stat_tables;
set @@histogram_size= @save_histogram_size;
set @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
...@@ -226,7 +226,8 @@ explain select * from t1 where a=1 or b=1 { ...@@ -226,7 +226,8 @@ explain select * from t1 where a=1 or b=1 {
], ],
"chosen_access_method": { "chosen_access_method": {
"type": "index_merge", "type": "index_merge",
"records": 2, "records_read": 2,
"records_out": 2,
"cost": 2.601171589, "cost": 2.601171589,
"uses_join_buffering": false "uses_join_buffering": false
} }
......
...@@ -226,7 +226,8 @@ explain select * from t1 where pk1 != 0 and key1 = 1 { ...@@ -226,7 +226,8 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
], ],
"chosen_access_method": { "chosen_access_method": {
"type": "ref", "type": "ref",
"records": 1, "records_read": 1,
"records_out": 1,
"cost": 1.250146475, "cost": 1.250146475,
"uses_join_buffering": false "uses_join_buffering": false
} }
......
...@@ -110,7 +110,8 @@ select * from db1.t1 { ...@@ -110,7 +110,8 @@ select * from db1.t1 {
], ],
"chosen_access_method": { "chosen_access_method": {
"type": "scan", "type": "scan",
"records": 3, "records_read": 3,
"records_out": 3,
"cost": 1.752563477, "cost": 1.752563477,
"uses_join_buffering": false "uses_join_buffering": false
} }
...@@ -248,7 +249,8 @@ select * from db1.v1 { ...@@ -248,7 +249,8 @@ select * from db1.v1 {
], ],
"chosen_access_method": { "chosen_access_method": {
"type": "scan", "type": "scan",
"records": 3, "records_read": 3,
"records_out": 3,
"cost": 1.752563477, "cost": 1.752563477,
"uses_join_buffering": false "uses_join_buffering": false
} }
......
...@@ -86,7 +86,8 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) ...@@ -86,7 +86,8 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
"chosen_access_method": "chosen_access_method":
{ {
"type": "index_merge", "type": "index_merge",
"records": 7, "records_read": 7,
"records_out": 7,
"cost": 13.79559815, "cost": 13.79559815,
"uses_join_buffering": false "uses_join_buffering": false
} }
...@@ -177,7 +178,8 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans')) ...@@ -177,7 +178,8 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
"chosen_access_method": "chosen_access_method":
{ {
"type": "ref", "type": "ref",
"records": 6, "records_read": 6,
"records_out": 0.6,
"cost": 5.002343464, "cost": 5.002343464,
"uses_join_buffering": false "uses_join_buffering": false
} }
......
...@@ -689,15 +689,15 @@ void print_final_join_order(JOIN *join) ...@@ -689,15 +689,15 @@ void print_final_join_order(JOIN *join)
} }
void print_best_access_for_table(THD *thd, POSITION *pos, void print_best_access_for_table(THD *thd, POSITION *pos)
enum join_type type)
{ {
DBUG_ASSERT(thd->trace_started()); DBUG_ASSERT(thd->trace_started());
Json_writer_object obj(thd, "chosen_access_method"); Json_writer_object obj(thd, "chosen_access_method");
obj. obj.
add("type", type == JT_ALL ? "scan" : join_type_str[type]). add("type", pos->type == JT_ALL ? "scan" : join_type_str[pos->type]).
add("records", pos->records_read). add("records_read", pos->records_read).
add("records_out", pos->records_out).
add("cost", pos->read_time). add("cost", pos->read_time).
add("uses_join_buffering", pos->use_join_buffer); add("uses_join_buffering", pos->use_join_buffer);
if (pos->range_rowid_filter_info) if (pos->range_rowid_filter_info)
......
...@@ -109,8 +109,7 @@ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex, ...@@ -109,8 +109,7 @@ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab); void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab);
void trace_plan_prefix(JOIN *join, uint idx, table_map join_tables); void trace_plan_prefix(JOIN *join, uint idx, table_map join_tables);
void print_final_join_order(JOIN *join); void print_final_join_order(JOIN *join);
void print_best_access_for_table(THD *thd, POSITION *pos, void print_best_access_for_table(THD *thd, POSITION *pos);
enum join_type type);
void trace_condition(THD * thd, const char *name, const char *transform_type, void trace_condition(THD * thd, const char *name, const char *transform_type,
Item *item, const char *table_name= nullptr); Item *item, const char *table_name= nullptr);
......
...@@ -460,10 +460,16 @@ void Range_rowid_filter_cost_info::trace_info(THD *thd) ...@@ -460,10 +460,16 @@ void Range_rowid_filter_cost_info::trace_info(THD *thd)
@brief @brief
Choose the best range filter for the given access of the table Choose the best range filter for the given access of the table
@param access_key_no The index by which the table is accessed @param access_key_no The index by which the table is accessed
@param records The estimated total number of key tuples with this access @param records The estimated total number of key tuples with
@param access_cost_factor the cost of a random seek to access the table this access
@param fetch_cost_factor The cost of fetching 'records' rows
@param index_only_cost The cost of fetching 'records' rows with
index only reads
@param prev_records How many row combinations we have in
preceding tables
@parma records_out Will be updated to the minimum result rows for any
usable filter.
@details @details
The function looks through the array of cost info for range filters The function looks through the array of cost info for range filters
and chooses the element for the range filter that promise the greatest and chooses the element for the range filter that promise the greatest
...@@ -478,7 +484,8 @@ TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no, ...@@ -478,7 +484,8 @@ TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no,
double records, double records,
double fetch_cost, double fetch_cost,
double index_only_cost, double index_only_cost,
double prev_records) double prev_records,
double *records_out)
{ {
if (range_rowid_filter_cost_info_elems == 0 || if (range_rowid_filter_cost_info_elems == 0 ||
covering_keys.is_set(access_key_no)) covering_keys.is_set(access_key_no))
...@@ -521,13 +528,14 @@ TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no, ...@@ -521,13 +528,14 @@ TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no,
continue; continue;
new_records= records * filter->selectivity; new_records= records * filter->selectivity;
set_if_smaller(*records_out, new_records);
cost_of_accepted_rows= fetch_cost * filter->selectivity; cost_of_accepted_rows= fetch_cost * filter->selectivity;
cost_of_rejected_rows= index_only_cost * (1 - filter->selectivity); cost_of_rejected_rows= index_only_cost * (1 - filter->selectivity);
new_cost= (cost_of_accepted_rows + cost_of_rejected_rows + new_cost= (cost_of_accepted_rows + cost_of_rejected_rows +
records * filter->lookup_cost()); records * filter->lookup_cost());
new_total_cost= ((new_cost + new_records * new_total_cost= ((new_cost + new_records *
in_use->variables.optimizer_where_cost) * prev_records + in_use->variables.optimizer_where_cost) *
filter->get_setup_cost()); prev_records + filter->get_setup_cost());
if (best_filter_gain > new_total_cost) if (best_filter_gain > new_total_cost)
{ {
......
...@@ -491,7 +491,8 @@ class Range_rowid_filter_cost_info final: public Sql_alloc ...@@ -491,7 +491,8 @@ class Range_rowid_filter_cost_info final: public Sql_alloc
double records, double records,
double fetch_cost, double fetch_cost,
double index_only_cost, double index_only_cost,
double prev_records); double prev_records,
double *records_out);
Range_rowid_filter_cost_info * Range_rowid_filter_cost_info *
apply_filter(THD *thd, TABLE *table, double *cost, double *records_arg, apply_filter(THD *thd, TABLE *table, double *cost, double *records_arg,
double *startup_cost, double fetch_cost, double *startup_cost, double fetch_cost,
......
...@@ -89,6 +89,18 @@ ...@@ -89,6 +89,18 @@
*/ */
#define HASH_FANOUT 0.1 #define HASH_FANOUT 0.1
/*
The following is used to check that A <= B, but with some margin as the
calculation is done slightly differently (mathematically correct, but
double calculations are not exact).
This is only used when comparing read rows and output rows, which
means that we can assume that both values are >= 0 and B cannot be notable
smaller than A.
*/
#define crash_if_first_double_is_bigger(A,B) DBUG_ASSERT(((A) == 0.0 && (B) == 0.0) || (A)/(B) < 1.0000001)
/* Cost for reading a row through an index */ /* Cost for reading a row through an index */
struct INDEX_READ_COST struct INDEX_READ_COST
{ {
...@@ -318,7 +330,7 @@ static JOIN_TAB *next_breadth_first_tab(JOIN_TAB *first_top_tab, ...@@ -318,7 +330,7 @@ static JOIN_TAB *next_breadth_first_tab(JOIN_TAB *first_top_tab,
static bool find_order_in_list(THD *, Ref_ptr_array, TABLE_LIST *, ORDER *, static bool find_order_in_list(THD *, Ref_ptr_array, TABLE_LIST *, ORDER *,
List<Item> &, List<Item> &, bool, bool, bool); List<Item> &, List<Item> &, bool, bool, bool);
static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, static double table_after_join_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
table_map rem_tables); table_map rem_tables);
void set_postjoin_aggr_write_func(JOIN_TAB *tab); void set_postjoin_aggr_write_func(JOIN_TAB *tab);
...@@ -421,7 +433,7 @@ bool dbug_user_var_equals_str(THD *thd, const char *name, const char* value) ...@@ -421,7 +433,7 @@ bool dbug_user_var_equals_str(THD *thd, const char *name, const char* value)
POSITION::POSITION() POSITION::POSITION()
{ {
table= 0; table= 0;
records_read= cond_selectivity= read_time= 0.0; records_read= cond_selectivity= read_time= records_out= 0.0;
prefix_record_count= 0.0; prefix_record_count= 0.0;
key= 0; key= 0;
use_join_buffer= 0; use_join_buffer= 0;
...@@ -5818,6 +5830,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, ...@@ -5818,6 +5830,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
Json_writer_object table_records(thd); Json_writer_object table_records(thd);
/* Only one matching row */ /* Only one matching row */
s->found_records= s->records= 1; s->found_records= s->records= 1;
s->records_out= 1.0;
s->read_time=1.0; s->read_time=1.0;
s->worst_seeks=1.0; s->worst_seeks=1.0;
table_records.add_table_name(s) table_records.add_table_name(s)
...@@ -7686,6 +7699,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key) ...@@ -7686,6 +7699,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
join->positions[idx].table= table; join->positions[idx].table= table;
join->positions[idx].key=key; join->positions[idx].key=key;
join->positions[idx].records_read=1.0; /* This is a const table */ join->positions[idx].records_read=1.0; /* This is a const table */
join->positions[idx].records_out=1.0; /* This is a const table */
join->positions[idx].cond_selectivity= 1.0; join->positions[idx].cond_selectivity= 1.0;
join->positions[idx].ref_depend_map= 0; join->positions[idx].ref_depend_map= 0;
...@@ -8022,6 +8036,7 @@ best_access_path(JOIN *join, ...@@ -8022,6 +8036,7 @@ best_access_path(JOIN *join,
my_bool found_constraint= 0; my_bool found_constraint= 0;
double best_cost= DBL_MAX; double best_cost= DBL_MAX;
double records= DBL_MAX; double records= DBL_MAX;
double records_out= table->stat_records() * table->cond_selectivity;
table_map best_ref_depends_map= 0; table_map best_ref_depends_map= 0;
/* /*
key_dependent is 0 if all key parts could be used or if there was an key_dependent is 0 if all key parts could be used or if there was an
...@@ -8317,9 +8332,12 @@ best_access_path(JOIN *join, ...@@ -8317,9 +8332,12 @@ best_access_path(JOIN *join,
(1.0 + (1.0 +
((double) (table->s->max_key_length-keyinfo->key_length) / ((double) (table->s->max_key_length-keyinfo->key_length) /
(double) table->s->max_key_length))); (double) table->s->max_key_length)));
set_if_smaller(records, (double)s->records);
set_if_smaller(records_out, records);
if (records < 2.0) if (records < 2.0)
records=2.0; /* Can't be as good as a unique */ records=2.0; /* Can't be as good as a unique */
} }
/* /*
ReuseRangeEstimateForRef-2: We get here if we could not reuse ReuseRangeEstimateForRef-2: We get here if we could not reuse
E(#rows) from range optimizer. Make another try: E(#rows) from range optimizer. Make another try:
...@@ -8357,9 +8375,10 @@ best_access_path(JOIN *join, ...@@ -8357,9 +8375,10 @@ best_access_path(JOIN *join,
} }
} }
/* Calculate the cost of the index access */ /* Calculate the cost of the index access */
INDEX_READ_COST cost= cost_for_index_read(thd, table, key, INDEX_READ_COST cost=
(ha_rows) records, cost_for_index_read(thd, table, key,
(ha_rows) s->worst_seeks); (ha_rows) records,
(ha_rows) s->worst_seeks);
tmp= cost.read_cost; tmp= cost.read_cost;
index_only_cost= cost.index_only_cost; index_only_cost= cost.index_only_cost;
} }
...@@ -8631,7 +8650,8 @@ best_access_path(JOIN *join, ...@@ -8631,7 +8650,8 @@ best_access_path(JOIN *join,
records, records,
tmp, tmp,
index_only_cost, index_only_cost,
record_count); record_count,
&records_out);
if (filter) if (filter)
filter= filter->apply_filter(thd, table, &tmp, &records_after_filter, filter= filter->apply_filter(thd, table, &tmp, &records_after_filter,
&startup_cost, &startup_cost,
...@@ -8673,6 +8693,7 @@ best_access_path(JOIN *join, ...@@ -8673,6 +8693,7 @@ best_access_path(JOIN *join,
add("chosen", false). add("chosen", false).
add("cause", cause ? cause : "cost"); add("cause", cause ? cause : "cost");
} }
set_if_smaller(records_out, records);
} /* for each key */ } /* for each key */
records= best_records; records= best_records;
} }
...@@ -8726,6 +8747,8 @@ best_access_path(JOIN *join, ...@@ -8726,6 +8747,8 @@ best_access_path(JOIN *join,
/* Estimate the cost of the hash join access to the table */ /* Estimate the cost of the hash join access to the table */
double rnd_records= matching_candidates_in_table(s, found_constraint, double rnd_records= matching_candidates_in_table(s, found_constraint,
use_cond_selectivity); use_cond_selectivity);
set_if_smaller(records_out, rnd_records);
/* /*
The following cost calculation is identical to the cost calculation for The following cost calculation is identical to the cost calculation for
the join cache later on, except for the HASH_FANOUT the join cache later on, except for the HASH_FANOUT
...@@ -8876,7 +8899,8 @@ best_access_path(JOIN *join, ...@@ -8876,7 +8899,8 @@ best_access_path(JOIN *join,
table->best_range_rowid_filter_for_partial_join(key_no, rows2double(range->rows), table->best_range_rowid_filter_for_partial_join(key_no, rows2double(range->rows),
range->find_cost, range->find_cost,
range->index_only_cost, range->index_only_cost,
record_count); record_count,
&records_out);
if (filter) if (filter)
{ {
double filter_cost= range->fetch_cost; double filter_cost= range->fetch_cost;
...@@ -8905,6 +8929,7 @@ best_access_path(JOIN *join, ...@@ -8905,6 +8929,7 @@ best_access_path(JOIN *join,
{ {
type= JT_INDEX_MERGE; type= JT_INDEX_MERGE;
} }
set_if_smaller(records_out, records_after_filter);
loose_scan_opt.check_range_access(join, idx, s->quick); loose_scan_opt.check_range_access(join, idx, s->quick);
} }
else else
...@@ -8913,7 +8938,10 @@ best_access_path(JOIN *join, ...@@ -8913,7 +8938,10 @@ best_access_path(JOIN *join,
rnd_records= matching_candidates_in_table(s, found_constraint, rnd_records= matching_candidates_in_table(s, found_constraint,
use_cond_selectivity); use_cond_selectivity);
records_after_filter= rnd_records; records_after_filter= rnd_records;
set_if_smaller(records_out, rnd_records);
org_records= rows2double(s->records); org_records= rows2double(s->records);
DBUG_ASSERT(rnd_records <= s->records); DBUG_ASSERT(rnd_records <= s->records);
/* Estimate cost of reading table. */ /* Estimate cost of reading table. */
...@@ -9043,7 +9071,9 @@ best_access_path(JOIN *join, ...@@ -9043,7 +9071,9 @@ best_access_path(JOIN *join,
} }
/* Update the cost information for the current partial plan */ /* Update the cost information for the current partial plan */
crash_if_first_double_is_bigger(records_out, records);
pos->records_read= records; pos->records_read= records;
pos->records_out= records_out;
pos->read_time= best_cost; pos->read_time= best_cost;
pos->key= best_key; pos->key= best_key;
pos->type= best_type; pos->type= best_type;
...@@ -9070,7 +9100,7 @@ best_access_path(JOIN *join, ...@@ -9070,7 +9100,7 @@ best_access_path(JOIN *join,
trace_paths.end(); trace_paths.end();
if (unlikely(thd->trace_started())) if (unlikely(thd->trace_started()))
print_best_access_for_table(thd, pos, best_type); print_best_access_for_table(thd, pos);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -9575,8 +9605,8 @@ optimize_straight_join(JOIN *join, table_map remaining_tables) ...@@ -9575,8 +9605,8 @@ optimize_straight_join(JOIN *join, table_map remaining_tables)
remaining_tables&= ~(s->table->map); remaining_tables&= ~(s->table->map);
double pushdown_cond_selectivity= 1.0; double pushdown_cond_selectivity= 1.0;
if (use_cond_selectivity > 1) if (use_cond_selectivity > 1)
pushdown_cond_selectivity= table_cond_selectivity(join, idx, s, pushdown_cond_selectivity= table_after_join_selectivity(join, idx, s,
remaining_tables); remaining_tables);
position->cond_selectivity= pushdown_cond_selectivity; position->cond_selectivity= pushdown_cond_selectivity;
++idx; ++idx;
} }
...@@ -10113,8 +10143,8 @@ double table_multi_eq_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, ...@@ -10113,8 +10143,8 @@ double table_multi_eq_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
*/ */
static static
double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, double table_after_join_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
table_map rem_tables) table_map rem_tables)
{ {
uint16 ref_keyuse_steps_buf[MAX_REF_PARTS]; uint16 ref_keyuse_steps_buf[MAX_REF_PARTS];
uint ref_keyuse_size= MAX_REF_PARTS; uint ref_keyuse_size= MAX_REF_PARTS;
...@@ -10890,9 +10920,10 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10890,9 +10920,10 @@ best_extension_by_limited_search(JOIN *join,
pushdown_cond_selectivity= 1.0; pushdown_cond_selectivity= 1.0;
if (use_cond_selectivity > 1) if (use_cond_selectivity > 1)
pushdown_cond_selectivity= table_cond_selectivity(join, idx, s, pushdown_cond_selectivity=
remaining_tables & table_after_join_selectivity(join, idx, s,
~real_table_bit); remaining_tables & ~real_table_bit);
join->positions[idx].cond_selectivity= pushdown_cond_selectivity; join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
partial_join_cardinality= (current_record_count * partial_join_cardinality= (current_record_count *
...@@ -10903,8 +10934,9 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10903,8 +10934,9 @@ best_extension_by_limited_search(JOIN *join,
.add("selectivity", pushdown_cond_selectivity) .add("selectivity", pushdown_cond_selectivity)
.add("estimated_join_cardinality", partial_join_cardinality); .add("estimated_join_cardinality", partial_join_cardinality);
if ((search_depth > 1) && if (search_depth > 1 &&
((remaining_tables & ~real_table_bit) & allowed_tables)) ((remaining_tables & ~real_table_bit) & allowed_tables))
{ {
/* Recursively expand the current partial plan */ /* Recursively expand the current partial plan */
Json_writer_array trace_rest(thd, "rest_of_plan"); Json_writer_array trace_rest(thd, "rest_of_plan");
...@@ -11715,6 +11747,7 @@ bool JOIN::get_best_combination() ...@@ -11715,6 +11747,7 @@ bool JOIN::get_best_combination()
*/ */
SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info; SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info;
j->records_read= (sjm->is_sj_scan? sjm->rows : 1.0); j->records_read= (sjm->is_sj_scan? sjm->rows : 1.0);
j->records_out= j->records_read;
j->records= (ha_rows) j->records_read; j->records= (ha_rows) j->records_read;
j->cond_selectivity= 1.0; j->cond_selectivity= 1.0;
JOIN_TAB *jt; JOIN_TAB *jt;
...@@ -11770,8 +11803,15 @@ bool JOIN::get_best_combination() ...@@ -11770,8 +11803,15 @@ bool JOIN::get_best_combination()
to access join->best_positions[]. to access join->best_positions[].
*/ */
j->records_read= best_positions[tablenr].records_read; j->records_read= best_positions[tablenr].records_read;
j->records_out= best_positions[tablenr].records_out;
j->cond_selectivity= best_positions[tablenr].cond_selectivity; j->cond_selectivity= best_positions[tablenr].cond_selectivity;
DBUG_ASSERT(j->cond_selectivity <= 1.0); DBUG_ASSERT(j->cond_selectivity <= 1.0);
crash_if_first_double_is_bigger(j->records_out,
j->records_read *
(j->range_rowid_filter_info ?
j->range_rowid_filter_info->selectivity :
1.0));
map2table[j->table->tablenr]= j; map2table[j->table->tablenr]= j;
/* If we've reached the end of sjm nest, switch back to main sequence */ /* If we've reached the end of sjm nest, switch back to main sequence */
...@@ -13071,7 +13111,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -13071,7 +13111,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
/* Fix for EXPLAIN */ /* Fix for EXPLAIN */
if (sel->quick) if (sel->quick)
join->best_positions[i].records_read= (double)sel->quick->records; {
join->best_positions[i].records_read=
(double) sel->quick->records;
set_if_smaller(join->best_positions[i].records_out,
join->best_positions[i].records_read);
}
} }
else else
{ {
...@@ -18542,9 +18587,10 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab, ...@@ -18542,9 +18587,10 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
table_map real_table_bit= rs->table->map; table_map real_table_bit= rs->table->map;
if (join->thd->variables.optimizer_use_condition_selectivity > 1) if (join->thd->variables.optimizer_use_condition_selectivity > 1)
{ {
pushdown_cond_selectivity= table_cond_selectivity(join, i, rs, pushdown_cond_selectivity=
reopt_remaining_tables & table_after_join_selectivity(join, i, rs,
~real_table_bit); reopt_remaining_tables &
~real_table_bit);
} }
(*outer_rec_count) *= pushdown_cond_selectivity; (*outer_rec_count) *= pushdown_cond_selectivity;
if (!rs->emb_sj_nest) if (!rs->emb_sj_nest)
...@@ -22673,7 +22719,7 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos) ...@@ -22673,7 +22719,7 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos)
{ // Info for DESCRIBE { // Info for DESCRIBE
tab->info= ET_CONST_ROW_NOT_FOUND; tab->info= ET_CONST_ROW_NOT_FOUND;
/* Mark for EXPLAIN that the row was not found */ /* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0; pos->records_read= pos->records_out= 0.0;
pos->ref_depend_map= 0; pos->ref_depend_map= 0;
if (!table->pos_in_table_list->outer_join || error > 0) if (!table->pos_in_table_list->outer_join || error > 0)
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -22691,7 +22737,7 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos) ...@@ -22691,7 +22737,7 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos)
{ {
tab->info= ET_UNIQUE_ROW_NOT_FOUND; tab->info= ET_UNIQUE_ROW_NOT_FOUND;
/* Mark for EXPLAIN that the row was not found */ /* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0; pos->records_read= pos->records_out= 0.0;
pos->ref_depend_map= 0; pos->ref_depend_map= 0;
if (!table->pos_in_table_list->outer_join || error > 0) if (!table->pos_in_table_list->outer_join || error > 0)
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -343,7 +343,10 @@ typedef struct st_join_table { ...@@ -343,7 +343,10 @@ typedef struct st_join_table {
/* Copy of POSITION::records_read, set by get_best_combination() */ /* Copy of POSITION::records_read, set by get_best_combination() */
double records_read; double records_read;
/* Copy of POSITION::records_out, set by get_best_combination() */
double records_out;
/* The selectivity of the conditions that can be pushed to the table */ /* The selectivity of the conditions that can be pushed to the table */
double cond_selectivity; double cond_selectivity;
...@@ -938,12 +941,23 @@ class POSITION ...@@ -938,12 +941,23 @@ class POSITION
/* The table that's put into join order */ /* The table that's put into join order */
JOIN_TAB *table; JOIN_TAB *table;
/*
The number of rows that will be read from the table
*/
double records_read;
/* /*
The "fanout": number of output rows that will be produced (after The "fanout": number of output rows that will be produced (after
pushed down selection condition is applied) per each row combination of pushed down selection condition is applied) per each row combination of
previous tables. previous tables.
This takes into account table->cond_selectivity, the WHERE clause
related to this table calculated in
calculate_cond_selectivity_for_table(), and the used rowid filter but
does not take into account the WHERE clause involving preceding tables
calculated in table_after_join_selectivity().
*/ */
double records_read; double records_out;
/* The selectivity of the pushed down conditions */ /* The selectivity of the pushed down conditions */
double cond_selectivity; double cond_selectivity;
...@@ -1007,6 +1021,7 @@ class POSITION ...@@ -1007,6 +1021,7 @@ class POSITION
/* Type of join (EQ_REF, REF etc) */ /* Type of join (EQ_REF, REF etc) */
enum join_type type; enum join_type type;
/* /*
Valid only after fix_semijoin_strategies_for_picked_join_order() call: Valid only after fix_semijoin_strategies_for_picked_join_order() call:
if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that if sj_strategy!=SJ_OPT_NONE, this is the number of subsequent tables that
......
...@@ -1810,7 +1810,8 @@ struct TABLE ...@@ -1810,7 +1810,8 @@ struct TABLE
double records, double records,
double fetch_cost, double fetch_cost,
double index_only_cost, double index_only_cost,
double prev_records); double prev_records,
double *records_out);
/** /**
System Versioning support System Versioning support
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment