summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/rowid_filter.h11
-rw-r--r--sql/sql_analyze_stmt.h7
-rw-r--r--sql/sql_explain.cc1
-rw-r--r--sql/sql_select.cc50
4 files changed, 62 insertions, 7 deletions
diff --git a/sql/rowid_filter.h b/sql/rowid_filter.h
index 467b6884ca6..b76b8b1e635 100644
--- a/sql/rowid_filter.h
+++ b/sql/rowid_filter.h
@@ -192,6 +192,9 @@ public:
*/
virtual bool check(void *ctxt, char *elem) = 0;
+ /* True if the container does not contain any element */
+ virtual bool is_empty() = 0;
+
virtual ~Rowid_filter_container() {}
};
@@ -231,6 +234,8 @@ public:
virtual ~Rowid_filter() {}
+ bool is_empty() { return container->is_empty(); }
+
Rowid_filter_container *get_container() { return container; }
void set_tracker(Rowid_filter_tracker *track_arg) { tracker= track_arg; }
@@ -268,6 +273,8 @@ public:
bool check(char *elem)
{
+ if (container->is_empty())
+ return false;
bool was_checked= container->check(table, elem);
tracker->increment_checked_elements_count(was_checked);
return was_checked;
@@ -339,6 +346,8 @@ public:
my_qsort2(array->front(), array->elements()/elem_size,
elem_size, (qsort2_cmp) cmp, cmp_arg);
}
+
+ bool is_empty() { return elements() == 0; }
};
@@ -368,6 +377,8 @@ public:
bool add(void *ctxt, char *elem) { return refpos_container.add(elem); }
bool check(void *ctxt, char *elem);
+
+ bool is_empty() { return refpos_container.is_empty(); }
};
/**
diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h
index 990c79fb9ad..968b8d38295 100644
--- a/sql/sql_analyze_stmt.h
+++ b/sql/sql_analyze_stmt.h
@@ -416,12 +416,13 @@ public:
uint get_container_elements() const { return container_elements; }
+ uint get_container_lookups() { return n_checks; }
+
double get_r_selectivity_pct() const
{
- return static_cast<double>(n_positive_checks) /
- static_cast<double>(n_checks);
+ return n_checks ? static_cast<double>(n_positive_checks) /
+ static_cast<double>(n_checks) : 0;
}
size_t get_container_buff_size() const { return container_buff_size; }
};
-
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index 539e427ee2f..1b59dce10b9 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -1676,6 +1676,7 @@ void Explain_rowid_filter::print_explain_json(Explain_query *query,
if (is_analyze)
{
writer->add_member("r_rows").add_double(tracker->get_container_elements());
+ writer->add_member("r_lookups").add_ll(tracker->get_container_lookups());
writer->add_member("r_selectivity_pct").
add_double(tracker->get_r_selectivity_pct() * 100.0);
writer->add_member("r_buffer_size").
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 81c4991e801..3d880365d42 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7496,9 +7496,11 @@ best_access_path(JOIN *join,
double best= DBL_MAX;
double best_time= DBL_MAX;
double records= DBL_MAX;
+ ha_rows records_for_key= 0;
table_map best_ref_depends_map= 0;
Range_rowid_filter_cost_info *best_filter= 0;
double tmp;
+ double keyread_tmp= 0;
ha_rows rec;
bool best_uses_jbuf= FALSE;
MY_BITMAP *eq_join_set= &s->table->eq_join_set;
@@ -7772,8 +7774,12 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
tmp= cost_for_index_read(thd, table, key, (ha_rows) records,
(ha_rows) s->worst_seeks);
+ records_for_key= (ha_rows) records;
+ set_if_smaller(records_for_key, thd->variables.max_seeks_for_key);
+ keyread_tmp= table->file->keyread_time(key, 1, records_for_key);
got_cost:
tmp= COST_MULT(tmp, record_count);
+ keyread_tmp= COST_MULT(keyread_tmp, record_count);
}
}
else
@@ -7950,12 +7956,14 @@ best_access_path(JOIN *join,
}
/* Limit the number of matched rows */
- tmp= records;
- set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- tmp= cost_for_index_read(thd, table, key, (ha_rows) tmp,
+ tmp= cost_for_index_read(thd, table, key, (ha_rows) records,
(ha_rows) s->worst_seeks);
+ records_for_key= (ha_rows) records;
+ set_if_smaller(records_for_key, thd->variables.max_seeks_for_key);
+ keyread_tmp= table->file->keyread_time(key, 1, records_for_key);
got_cost2:
tmp= COST_MULT(tmp, record_count);
+ keyread_tmp= COST_MULT(keyread_tmp, record_count);
}
else
{
@@ -7974,7 +7982,35 @@ best_access_path(JOIN *join,
(found_part & 1)) // start_key->key can be used for index access
{
double rows= record_count * records;
- double access_cost_factor= MY_MIN(tmp / rows, 1.0);
+
+ /*
+ If we use filter F with selectivity s the the cost of fetching data
+ by key using this filter will be
+ cost_of_fetching_1_row * rows * s +
+ cost_of_fetching_1_key_tuple * rows * (1 - s) +
+ cost_of_1_lookup_into_filter * rows
+ Without using any filter the cost would be just
+ cost_of_fetching_1_row * rows
+
+ So the gain in access cost per row will be
+ cost_of_fetching_1_row * (1 - s) -
+ cost_of_fetching_1_key_tuple * (1 - s) -
+ cost_of_1_lookup_into_filter
+ =
+ (cost_of_fetching_1_row - cost_of_fetching_1_key_tuple) * (1 - s)
+ - cost_of_1_lookup_into_filter
+
+ Here we have:
+ cost_of_fetching_1_row = tmp/rows
+ cost_of_fetching_1_key_tuple = keyread_tmp/rows
+
+ Note that access_cost_factor may be greater than 1.0. In this case
+ we still can expect a gain of using rowid filter due to smaller number
+ of checks for conditions pushed to the joined table.
+ */
+ double rows_access_cost= MY_MIN(rows, s->worst_seeks);
+ double access_cost_factor= MY_MIN((rows_access_cost - keyread_tmp) /
+ rows, 1.0);
filter=
table->best_range_rowid_filter_for_partial_join(start_key->key, rows,
access_cost_factor);
@@ -8135,6 +8171,10 @@ best_access_path(JOIN *join,
double rows= record_count * s->found_records;
double access_cost_factor= MY_MIN(tmp / rows, 1.0);
uint key_no= s->quick->index;
+
+ /* See the comment concerning using rowid filter for with ref access */
+ keyread_tmp= s->table->opt_range[key_no].index_only_cost;
+ access_cost_factor= MY_MIN((rows - keyread_tmp) / rows, 1.0);
filter=
s->table->best_range_rowid_filter_for_partial_join(key_no, rows,
access_cost_factor);
@@ -20929,6 +20969,8 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
DBUG_RETURN(NESTED_LOOP_ERROR);
join_tab->build_range_rowid_filter_if_needed();
+ if (join_tab->rowid_filter && join_tab->rowid_filter->is_empty())
+ rc= NESTED_LOOP_NO_MORE_ROWS;
join->return_tab= join_tab;