mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-406: ANALYZE $stmt: add support for BNL join buffering
This commit is contained in:
@ -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;
|
|||||||
--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
|
|||||||
}
|
}
|
||||||
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
|
|||||||
{
|
{
|
||||||
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 @@ public:
|
|||||||
{
|
{
|
||||||
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
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
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 @@ public:
|
|||||||
|
|
||||||
/* 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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
/* 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)
|
|||||||
|
|
||||||
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 @@ finish:
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
|||||||
{
|
{
|
||||||
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()
|
|||||||
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()
|
|||||||
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 {
|
|||||||
|
|
||||||
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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
/* 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 @@ public:
|
|||||||
/* 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,
|
|||||||
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
|
|||||||
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 {
|
|||||||
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.
|
||||||
|
Reference in New Issue
Block a user