Commit 7711999d authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-406: ANALYZE $stmt: add support for BNL join buffering

parent c3cfb691
...@@ -79,4 +79,41 @@ analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1 where t ...@@ -79,4 +79,41 @@ analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1 where t
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 3 100.00 0.00 Using where 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 3 100.00 0.00 Using where
2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 NULL 100.00 NULL Using where 2 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 10 NULL 100.00 NULL Using where
drop table t0, t1;
#
# Tests for join buffering
#
create table t0 (a int, b int);
insert into t0 values
(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
create table t1 like t0;
insert into t1 select * from t0;
explain select * from t0, t1 where t0.a<5 and t1.a<5;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
# These should have filtered=50
analyze select * from t0, t1 where t0.a<5 and t1.a<5;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where; Using join buffer (flat, BNL join)
explain select * from t0, t1 where t0.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
# Now, t1 should have filtered=10
analyze select * from t0, t1 where t0.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 10.00 Using where; Using join buffer (flat, BNL join)
explain select * from t0, t1 where t0.a<5 and t1.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join)
# Now, t1 should have filtered=10
analyze select * from t0, t1 where t0.a<5 and t1.a<5 and t1.b=t0.b;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 10 10 100.00 50.00 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 10 10 100.00 10.00 Using where; Using join buffer (flat, BNL join)
drop table t0,t1; drop table t0,t1;
# TODO: Check what is counted for "range checked for each record".
...@@ -61,5 +61,30 @@ analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1; ...@@ -61,5 +61,30 @@ analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1;
--echo # Try a subquery that is never executed --echo # Try a subquery that is never executed
analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1 where t1.a > 5; analyze select a, a in (select t0.b from t0 where t0.b+1=t1.b+1) from t1 where t1.a > 5;
drop table t0, t1;
--echo #
--echo # Tests for join buffering
--echo #
create table t0 (a int, b int);
insert into t0 values
(0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
create table t1 like t0;
insert into t1 select * from t0;
explain select * from t0, t1 where t0.a<5 and t1.a<5;
--echo # These should have filtered=50
analyze select * from t0, t1 where t0.a<5 and t1.a<5;
explain select * from t0, t1 where t0.a<5 and t1.b=t0.b;
--echo # Now, t1 should have filtered=10
analyze select * from t0, t1 where t0.a<5 and t1.b=t0.b;
explain select * from t0, t1 where t0.a<5 and t1.a<5 and t1.b=t0.b;
--echo # Now, t1 should have filtered=10
analyze select * from t0, t1 where t0.a<5 and t1.a<5 and t1.b=t0.b;
drop table t0,t1; drop table t0,t1;
--echo # TODO: Check what is counted for "range checked for each record".
...@@ -585,12 +585,10 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai ...@@ -585,12 +585,10 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
} }
else else
{ {
double r_filtered; double r_filtered= tracker.get_filtered_after_where();
if (tracker.r_rows > 0) if (bka_type.is_using_jbuf())
r_filtered= 100.0 * (double)tracker.r_rows_after_table_cond / tracker.r_rows; r_filtered *= jbuf_tracker.get_filtered_after_where();
else item_list.push_back(new Item_float(r_filtered*100.0, 2));
r_filtered= 100.0;
item_list.push_back(new Item_float(r_filtered, 2));
} }
} }
......
...@@ -19,13 +19,13 @@ class Table_access_tracker ...@@ -19,13 +19,13 @@ class Table_access_tracker
{ {
public: public:
Table_access_tracker() : Table_access_tracker() :
r_scans(0), r_rows(0), r_rows_after_table_cond(0), r_scans(0), r_rows(0), /*r_rows_after_table_cond(0),*/
r_rows_after_where(0) r_rows_after_where(0)
{} {}
ha_rows r_scans; /* How many scans were ran on this join_tab */ ha_rows r_scans; /* How many scans were ran on this join_tab */
ha_rows r_rows; /* How many rows we've got after that */ ha_rows r_rows; /* How many rows we've got after that */
ha_rows r_rows_after_table_cond; /* Rows after applying the table condition */ // ha_rows r_rows_after_table_cond; /* Rows after applying the table condition */
ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */ ha_rows r_rows_after_where; /* Rows after applying attached part of WHERE */
bool has_scans() { return (r_scans != 0); } bool has_scans() { return (r_scans != 0); }
...@@ -33,6 +33,17 @@ class Table_access_tracker ...@@ -33,6 +33,17 @@ class Table_access_tracker
{ {
return r_scans ? (ha_rows)rint((double) r_rows / r_scans): 0; return r_scans ? (ha_rows)rint((double) r_rows / r_scans): 0;
} }
double get_filtered_after_where()
{
double r_filtered;
if (r_rows > 0)
r_filtered= (double)r_rows_after_where / r_rows;
else
r_filtered= 1.0;
return r_filtered;
}
}; };
...@@ -371,13 +382,17 @@ enum explain_extra_tag ...@@ -371,13 +382,17 @@ enum explain_extra_tag
}; };
typedef struct st_explain_bka_type class EXPLAIN_BKA_TYPE
{ {
public:
EXPLAIN_BKA_TYPE() : join_alg(NULL) {}
bool incremental; bool incremental;
const char *join_alg; const char *join_alg;
StringBuffer<64> mrr_type; StringBuffer<64> mrr_type;
} EXPLAIN_BKA_TYPE; bool is_using_jbuf() { return (join_alg != NULL); }
};
/* /*
...@@ -517,6 +532,7 @@ class Explain_table_access : public Sql_alloc ...@@ -517,6 +532,7 @@ class Explain_table_access : public Sql_alloc
/* ANALYZE members*/ /* ANALYZE members*/
Table_access_tracker tracker; Table_access_tracker tracker;
Table_access_tracker jbuf_tracker;
private: private:
void append_tag_name(String *str, enum explain_extra_tag tag); void append_tag_name(String *str, enum explain_extra_tag tag);
......
...@@ -2254,7 +2254,7 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last) ...@@ -2254,7 +2254,7 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
*/ */
goto finish; goto finish;
} }
while (!(error= join_tab_scan->next())) while (!(error= join_tab_scan->next()))
{ {
if (join->thd->check_killed()) if (join->thd->check_killed())
...@@ -2271,11 +2271,13 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last) ...@@ -2271,11 +2271,13 @@ enum_nested_loop_state JOIN_CACHE::join_matching_records(bool skip_last)
/* Prepare to read matching candidates from the join buffer */ /* Prepare to read matching candidates from the join buffer */
if (prepare_look_for_matches(skip_last)) if (prepare_look_for_matches(skip_last))
continue; continue;
join_tab->jbuf_tracker->r_scans++;
uchar *rec_ptr; uchar *rec_ptr;
/* Read each possible candidate from the buffer and look for matches */ /* Read each possible candidate from the buffer and look for matches */
while ((rec_ptr= get_next_candidate_for_match())) while ((rec_ptr= get_next_candidate_for_match()))
{ {
join_tab->jbuf_tracker->r_rows++;
/* /*
If only the first match is needed, and, it has been already found for If only the first match is needed, and, it has been already found for
the next record read from the join buffer, then the record is skipped. the next record read from the join buffer, then the record is skipped.
...@@ -2445,6 +2447,8 @@ inline bool JOIN_CACHE::check_match(uchar *rec_ptr) ...@@ -2445,6 +2447,8 @@ inline bool JOIN_CACHE::check_match(uchar *rec_ptr)
if (join_tab->select && join_tab->select->skip_record(join->thd) <= 0) if (join_tab->select && join_tab->select->skip_record(join->thd) <= 0)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
join_tab->jbuf_tracker->r_rows_after_where++;
if (!join_tab->is_last_inner_table()) if (!join_tab->is_last_inner_table())
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -2568,7 +2572,7 @@ enum_nested_loop_state JOIN_CACHE::join_null_complements(bool skip_last) ...@@ -2568,7 +2572,7 @@ enum_nested_loop_state JOIN_CACHE::join_null_complements(bool skip_last)
none none
*/ */
void JOIN_CACHE::save_explain_data(struct st_explain_bka_type *explain) void JOIN_CACHE::save_explain_data(EXPLAIN_BKA_TYPE *explain)
{ {
explain->incremental= MY_TEST(prev_cache); explain->incremental= MY_TEST(prev_cache);
...@@ -2613,14 +2617,14 @@ static void add_mrr_explain_info(String *str, uint mrr_mode, handler *file) ...@@ -2613,14 +2617,14 @@ static void add_mrr_explain_info(String *str, uint mrr_mode, handler *file)
} }
} }
void JOIN_CACHE_BKA::save_explain_data(struct st_explain_bka_type *explain) void JOIN_CACHE_BKA::save_explain_data(EXPLAIN_BKA_TYPE *explain)
{ {
JOIN_CACHE::save_explain_data(explain); JOIN_CACHE::save_explain_data(explain);
add_mrr_explain_info(&explain->mrr_type, mrr_mode, join_tab->table->file); add_mrr_explain_info(&explain->mrr_type, mrr_mode, join_tab->table->file);
} }
void JOIN_CACHE_BKAH::save_explain_data(struct st_explain_bka_type *explain) void JOIN_CACHE_BKAH::save_explain_data(EXPLAIN_BKA_TYPE *explain)
{ {
JOIN_CACHE::save_explain_data(explain); JOIN_CACHE::save_explain_data(explain);
add_mrr_explain_info(&explain->mrr_type, mrr_mode, join_tab->table->file); add_mrr_explain_info(&explain->mrr_type, mrr_mode, join_tab->table->file);
...@@ -3326,6 +3330,7 @@ int JOIN_TAB_SCAN::open() ...@@ -3326,6 +3330,7 @@ int JOIN_TAB_SCAN::open()
{ {
save_or_restore_used_tabs(join_tab, FALSE); save_or_restore_used_tabs(join_tab, FALSE);
is_first_record= TRUE; is_first_record= TRUE;
join_tab->tracker->r_scans++;
return join_init_read_record(join_tab); return join_init_read_record(join_tab);
} }
...@@ -3364,8 +3369,14 @@ int JOIN_TAB_SCAN::next() ...@@ -3364,8 +3369,14 @@ int JOIN_TAB_SCAN::next()
is_first_record= FALSE; is_first_record= FALSE;
else else
err= info->read_record(info); err= info->read_record(info);
if (!err && table->vfield)
update_virtual_fields(thd, table); if (!err)
{
join_tab->tracker->r_rows++;
if (table->vfield)
update_virtual_fields(thd, table);
}
while (!err && select && (skip_rc= select->skip_record(thd)) <= 0) while (!err && select && (skip_rc= select->skip_record(thd)) <= 0)
{ {
if (thd->check_killed() || skip_rc < 0) if (thd->check_killed() || skip_rc < 0)
...@@ -3375,9 +3386,16 @@ int JOIN_TAB_SCAN::next() ...@@ -3375,9 +3386,16 @@ int JOIN_TAB_SCAN::next()
meet the condition pushed to the table join_tab. meet the condition pushed to the table join_tab.
*/ */
err= info->read_record(info); err= info->read_record(info);
if (!err && table->vfield) if (!err)
update_virtual_fields(thd, table); {
} join_tab->tracker->r_rows++;
if (table->vfield)
update_virtual_fields(thd, table);
}
}
if (!err)
join_tab->tracker->r_rows_after_where++;
return err; return err;
} }
......
...@@ -63,7 +63,7 @@ typedef struct st_cache_field { ...@@ -63,7 +63,7 @@ typedef struct st_cache_field {
class JOIN_TAB_SCAN; class JOIN_TAB_SCAN;
struct st_explain_bka_type; class EXPLAIN_BKA_TYPE;
/* /*
JOIN_CACHE is the base class to support the implementations of JOIN_CACHE is the base class to support the implementations of
...@@ -659,7 +659,7 @@ class JOIN_CACHE :public Sql_alloc ...@@ -659,7 +659,7 @@ class JOIN_CACHE :public Sql_alloc
enum_nested_loop_state join_records(bool skip_last); enum_nested_loop_state join_records(bool skip_last);
/* Add a comment on the join algorithm employed by the join cache */ /* Add a comment on the join algorithm employed by the join cache */
virtual void save_explain_data(struct st_explain_bka_type *explain); virtual void save_explain_data(EXPLAIN_BKA_TYPE *explain);
THD *thd(); THD *thd();
...@@ -1337,7 +1337,7 @@ class JOIN_CACHE_BKA :public JOIN_CACHE ...@@ -1337,7 +1337,7 @@ class JOIN_CACHE_BKA :public JOIN_CACHE
/* Check index condition of the joined table for a record from BKA cache */ /* Check index condition of the joined table for a record from BKA cache */
bool skip_index_tuple(range_id_t range_info); bool skip_index_tuple(range_id_t range_info);
void save_explain_data(struct st_explain_bka_type *explain); void save_explain_data(EXPLAIN_BKA_TYPE *explain);
}; };
...@@ -1428,5 +1428,5 @@ class JOIN_CACHE_BKAH :public JOIN_CACHE_BNLH ...@@ -1428,5 +1428,5 @@ class JOIN_CACHE_BKAH :public JOIN_CACHE_BNLH
/* Check index condition of the joined table for a record from BKAH cache */ /* Check index condition of the joined table for a record from BKAH cache */
bool skip_index_tuple(range_id_t range_info); bool skip_index_tuple(range_id_t range_info);
void save_explain_data(struct st_explain_bka_type *explain); void save_explain_data(EXPLAIN_BKA_TYPE *explain);
}; };
...@@ -17731,7 +17731,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, ...@@ -17731,7 +17731,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
There is no select condition or the attached pushed down There is no select condition or the attached pushed down
condition is true => a match is found. condition is true => a match is found.
*/ */
join_tab->tracker->r_rows_after_table_cond++; join_tab->tracker->r_rows_after_where++;
bool found= 1; bool found= 1;
while (join_tab->first_unmatched && found) while (join_tab->first_unmatched && found)
{ {
...@@ -23308,6 +23308,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab ...@@ -23308,6 +23308,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
eta->quick_info= NULL; eta->quick_info= NULL;
tab->tracker= &eta->tracker; tab->tracker= &eta->tracker;
tab->jbuf_tracker= &eta->jbuf_tracker;
/* id */ /* id */
if (tab->bush_root_tab) if (tab->bush_root_tab)
......
...@@ -252,6 +252,7 @@ typedef struct st_join_table { ...@@ -252,6 +252,7 @@ typedef struct st_join_table {
enum explain_extra_tag info; enum explain_extra_tag info;
Table_access_tracker *tracker; Table_access_tracker *tracker;
Table_access_tracker *jbuf_tracker;
/* /*
Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra' Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info. column, or 0 if there is no info.
......
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