diff options
author | Galina Shalygina <galina.shalygina@mariadb.com> | 2019-02-06 23:40:07 +0300 |
---|---|---|
committer | Galina Shalygina <galina.shalygina@mariadb.com> | 2019-02-06 23:40:07 +0300 |
commit | 447e0f023fff0fa2ccfa7e93b77f1da3be3b43f1 (patch) | |
tree | 1210e525389dfa3e4b2fa00e22fb18bf29a7f016 /sql | |
parent | e299ae5b0786aa9348e422f4271fb344d51f60fa (diff) | |
download | mariadb-git-447e0f023fff0fa2ccfa7e93b77f1da3be3b43f1.tar.gz |
MDEV-18144: ANALYZE for statement support for PK filters
ANALYZE and ANALYZE FORMAT=JSON structures are changed in the way that they
show additional information when rowid filter is used:
- r_selectivity_pct - the observed filter selectivity
- r_buffer_size - the size of the rowid filter container buffer
- r_filling_time_ms - how long it took to fill rowid filter container
New class Rowid_filter_tracker was added. This class is needed to collect data
about how rowid filter is executed.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/rowid_filter.cc | 3 | ||||
-rw-r--r-- | sql/rowid_filter.h | 12 | ||||
-rw-r--r-- | sql/sql_analyze_stmt.h | 79 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_explain.cc | 34 | ||||
-rw-r--r-- | sql/sql_explain.h | 3 | ||||
-rw-r--r-- | sql/sql_select.cc | 18 |
8 files changed, 144 insertions, 8 deletions
diff --git a/sql/handler.h b/sql/handler.h index 27e38e9c36f..083636017db 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3014,6 +3014,7 @@ private: Exec_time_tracker *tracker; public: void set_time_tracker(Exec_time_tracker *tracker_arg) { tracker=tracker_arg;} + Exec_time_tracker *get_time_tracker() { return tracker; } Item *pushed_idx_cond; uint pushed_idx_cond_keyno; /* The index which the above condition is for */ diff --git a/sql/rowid_filter.cc b/sql/rowid_filter.cc index 4348eea081d..b2349d26843 100644 --- a/sql/rowid_filter.cc +++ b/sql/rowid_filter.cc @@ -478,6 +478,8 @@ bool Range_rowid_filter::fill() file->position(quick->record); if (container->add(NULL, (char*) file->ref)) rc= 1; + else + tracker->increment_container_elements_count(); } } @@ -488,6 +490,7 @@ bool Range_rowid_filter::fill() file->pushed_idx_cond= pushed_idx_cond_save; file->pushed_idx_cond_keyno= pushed_idx_cond_keyno_save; file->in_range_check_pushed_down= in_range_check_pushed_down_save; + tracker->report_container_buff_size(table->file->ref_length); if (rc != HA_ERR_END_OF_FILE) return 1; diff --git a/sql/rowid_filter.h b/sql/rowid_filter.h index 3cc2c31555c..de50fd36c4c 100644 --- a/sql/rowid_filter.h +++ b/sql/rowid_filter.h @@ -211,6 +211,8 @@ protected: /* The container to store info the set of elements in the filter */ Rowid_filter_container *container; + Rowid_filter_tracker *tracker; + public: Rowid_filter(Rowid_filter_container *container_arg) : container(container_arg) {} @@ -230,6 +232,9 @@ public: virtual ~Rowid_filter() {} Rowid_filter_container *get_container() { return container; } + + void set_tracker(Rowid_filter_tracker *track_arg) { tracker= track_arg; } + Rowid_filter_tracker *get_tracker() { return tracker; } }; @@ -261,7 +266,12 @@ public: bool build() { return fill(); } - bool check(char *elem) { return container->check(table, elem); } + bool check(char *elem) + { + bool was_checked= container->check(table, elem); + tracker->increment_checked_elements_count(was_checked); + return was_checked; + } bool fill(); diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h index 27fd7fb6d6a..ceda8b4f416 100644 --- a/sql/sql_analyze_stmt.h +++ b/sql/sql_analyze_stmt.h @@ -284,3 +284,82 @@ private: ulonglong sort_buffer_size; }; + +/** + A class to collect data about how rowid filter is executed. + + It stores information about how rowid filter container is filled, + containers size and observed selectivity. + + The observed selectivity is calculated in this way. + Some elements elem_set are checked if they belong to container. + Observed selectivity is calculated as the count of elem_set + elements that belong to container devided by all elem_set elements. +*/ + +class Rowid_filter_tracker : public Sql_alloc +{ +private: + /* A member to track the time to fill the rowid filter */ + Time_and_counter_tracker time_tracker; + + /* Size of the rowid filter container buffer */ + size_t container_buff_size; + + /* Count of elements that were used to fill the rowid filter container */ + uint container_elements; + + /* Elements counts used for observed selectivity calculation */ + uint n_checks; + uint n_positive_checks; +public: + Rowid_filter_tracker(bool do_timing) : + time_tracker(do_timing), container_buff_size(0), + container_elements(0), n_checks(0), n_positive_checks(0) + {} + + inline void start_tracking() + { + ANALYZE_START_TRACKING(&time_tracker); + } + + inline void stop_tracking() + { + ANALYZE_STOP_TRACKING(&time_tracker); + } + + /* Save container buffer size in bytes */ + inline void report_container_buff_size(uint elem_size) + { + container_buff_size= container_elements * elem_size / 8; + } + + Time_and_counter_tracker *get_time_tracker() + { + return &time_tracker; + } + + double get_time_fill_container_ms() + { + return time_tracker.get_time_ms(); + } + + void increment_checked_elements_count(bool was_checked) + { + n_checks++; + if (was_checked) + n_positive_checks++; + } + + inline void increment_container_elements_count() { container_elements++; } + + uint get_container_elements() { return container_elements; } + + double get_r_selectivity_pct() + { + return (double)n_positive_checks/(double)n_checks; + } + + size_t get_container_buff_size() { return container_buff_size; } +}; + diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e6453415475..42b94d95933 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2728,7 +2728,7 @@ void THD::make_explain_field_list(List<Item> &field_list, uint8 explain_flags, if (is_analyze) { field_list.push_back(item= new (mem_root) - Item_float(this, "r_rows", 0.1234, 10, 4), + Item_empty_string(this, "r_rows", NAME_CHAR_LEN, cs), mem_root); item->maybe_null=1; } diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index c7c6f15f7cc..0c2f49338fe 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -1324,6 +1324,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai item_list.push_back(item_null, mem_root); /* `r_rows` */ + StringBuffer<64> r_rows_str; if (is_analyze) { if (!tracker.has_scans()) @@ -1333,8 +1334,19 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai else { double avg_rows= tracker.get_avg_rows(); - item_list.push_back(new (mem_root) Item_float(thd, avg_rows, 2), - mem_root); + Item_float *fl= new (mem_root) Item_float(thd, avg_rows, 2); + String tmp; + String *res= fl->val_str(&tmp); + r_rows_str.append(res->ptr()); + if (rowid_filter) + { + r_rows_str.append(" ("); + r_rows_str.append_ulonglong(rowid_filter->tracker->get_r_selectivity_pct() * 100.0); + r_rows_str.append("%)"); + } + item_list.push_back(new (mem_root) + Item_string_sys(thd, r_rows_str.ptr(), + r_rows_str.length()), mem_root); } } @@ -1404,7 +1416,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai first= false; else extra_buf.append(STRING_WITH_LEN("; ")); - extra_buf.append(STRING_WITH_LEN("Using filter")); + extra_buf.append(STRING_WITH_LEN("Using rowid filter")); } item_list.push_back(new (mem_root) @@ -1604,6 +1616,16 @@ void Explain_rowid_filter::print_explain_json(Explain_query *query, quick->print_json(writer); writer->add_member("rows").add_ll(rows); writer->add_member("selectivity_pct").add_double(selectivity * 100.0); + if (is_analyze) + { + writer->add_member("r_rows").add_double(tracker->get_container_elements()); + writer->add_member("r_selectivity_pct"). + add_double(tracker->get_r_selectivity_pct() * 100.0); + writer->add_member("r_buffer_size"). + add_double(tracker->get_container_buff_size()); + writer->add_member("r_filling_time_ms"). + add_double(tracker->get_time_fill_container_ms()); + } writer->end_object(); // rowid_filter } @@ -1742,8 +1764,10 @@ void Explain_table_access::print_explain_json(Explain_query *query, if (op_tracker.get_loops()) { - writer->add_member("r_total_time_ms"). - add_double(op_tracker.get_time_ms()); + double total_time= op_tracker.get_time_ms(); + if (rowid_filter) + total_time+= rowid_filter->tracker->get_time_fill_container_ms(); + writer->add_member("r_total_time_ms").add_double(total_time); } } diff --git a/sql/sql_explain.h b/sql/sql_explain.h index a161f6c1049..08966b71faa 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -624,6 +624,9 @@ public: /* Expected selectivity for the filter */ double selectivity; + /* Tracker with the information about how rowid filter is executed */ + Rowid_filter_tracker *tracker; + void print_explain_json(Explain_query *query, Json_writer *writer, bool is_analyze); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a17682bd9c8..3d231345b73 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12619,6 +12619,18 @@ void JOIN_TAB::build_range_rowid_filter_if_needed() { if (rowid_filter && !is_rowid_filter_built) { + /** + The same handler object (table->file) is used to build a filter + and to perfom a primary table access (by the main query). + + To estimate the time for filter building tracker should be changed + and after building of the filter has been finished it should be + switched back to the previos tracker. + */ + Exec_time_tracker *table_tracker= table->file->get_time_tracker(); + Rowid_filter_tracker *rowid_tracker= rowid_filter->get_tracker(); + table->file->set_time_tracker(rowid_tracker->get_time_tracker()); + rowid_tracker->start_tracking(); if (!rowid_filter->build()) { is_rowid_filter_built= true; @@ -12628,6 +12640,8 @@ void JOIN_TAB::build_range_rowid_filter_if_needed() delete rowid_filter; rowid_filter= 0; } + rowid_tracker->stop_tracking(); + table->file->set_time_tracker(table_tracker); } } @@ -25408,8 +25422,10 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, erf->quick= quick->get_explain(thd->mem_root); erf->selectivity= range_rowid_filter_info->selectivity; erf->rows= quick->records; + if (!(erf->tracker= new Rowid_filter_tracker(thd->lex->analyze_stmt))) + return 1; + rowid_filter->set_tracker(erf->tracker); eta->rowid_filter= erf; - //psergey-todo: also do setup for ANALYZE here. } if (tab_type == JT_NEXT) |