Commit dba8cfd5 authored by Igor Babaev's avatar Igor Babaev

BNL and BNLH algorithms scan the join table and for each its record they

try to find a match in the join buffer. It makes sense to check for a match
only those records satisfying WHERE/ON conditions that can be pushed to
the scanned table. It allows us to discard early some join candidates.

Such pushdown conditions were built when BNL join algorithm was employed,
but for they were not built when BNLH algorithm was used.
The patch removes this shortcoming. 
parent 73898792
...@@ -180,11 +180,13 @@ int join_read_always_key_or_null(JOIN_TAB *tab); ...@@ -180,11 +180,13 @@ int join_read_always_key_or_null(JOIN_TAB *tab);
int join_read_next_same_or_null(READ_RECORD *info); int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(Item *cond,table_map table, static COND *make_cond_for_table(Item *cond,table_map table,
table_map used_table, table_map used_table,
bool exclude_expensive_cond); bool exclude_expensive_cond,
bool retain_ref_cond);
static COND *make_cond_for_table_from_pred(Item *root_cond, Item *cond, static COND *make_cond_for_table_from_pred(Item *root_cond, Item *cond,
table_map tables, table_map tables,
table_map used_table, table_map used_table,
bool exclude_expensive_cond); bool exclude_expensive_cond,
bool retain_ref_cond);
static Item* part_of_refkey(TABLE *form,Field *field); static Item* part_of_refkey(TABLE *form,Field *field);
uint find_shortest_key(TABLE *table, const key_map *usable_keys); uint find_shortest_key(TABLE *table, const key_map *usable_keys);
...@@ -927,7 +929,7 @@ JOIN::optimize() ...@@ -927,7 +929,7 @@ JOIN::optimize()
if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED)) if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED))
{ {
COND *table_independent_conds= COND *table_independent_conds=
make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0, FALSE); make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0, FALSE, FALSE);
DBUG_EXECUTE("where", DBUG_EXECUTE("where",
print_where(table_independent_conds, print_where(table_independent_conds,
"where after opt_sum_query()", "where after opt_sum_query()",
...@@ -2254,7 +2256,7 @@ JOIN::exec() ...@@ -2254,7 +2256,7 @@ JOIN::exec()
Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having, Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having,
used_tables, used_tables,
(table_map)0, FALSE); (table_map)0, FALSE, FALSE);
if (sort_table_cond) if (sort_table_cond)
{ {
if (!curr_table->select) if (!curr_table->select)
...@@ -2277,7 +2279,7 @@ JOIN::exec() ...@@ -2277,7 +2279,7 @@ JOIN::exec()
QT_ORDINARY);); QT_ORDINARY););
curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having, curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
~ (table_map) 0, ~ (table_map) 0,
~used_tables, FALSE); ~used_tables, FALSE, FALSE);
DBUG_EXECUTE("where",print_where(curr_join->tmp_having, DBUG_EXECUTE("where",print_where(curr_join->tmp_having,
"having after sort", "having after sort",
QT_ORDINARY);); QT_ORDINARY););
...@@ -5979,6 +5981,46 @@ bool JOIN_TAB::hash_join_is_possible() ...@@ -5979,6 +5981,46 @@ bool JOIN_TAB::hash_join_is_possible()
} }
/*
@brief
Extract pushdown conditions for a table scan
@details
This functions extracts pushdown conditions usable when this table is scanned.
The conditions are extracted either from WHERE or from ON expressions.
The conditions are attached to the field cache_select of this table.
@note
Currently the extracted conditions are used only by BNL and BNLH join.
algorithms.
@retval 0 on success
1 otherwise
*/
int JOIN_TAB::make_scan_filter()
{
COND *tmp;
DBUG_ENTER("make_join_select");
Item *cond= is_last_inner_table() ?
*get_first_inner_table()->on_expr_ref : join->conds;
if (cond &&
(tmp=make_cond_for_table(cond, join->const_table_map | table->map,
table->map, FALSE, TRUE)))
{
DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY););
if (!(cache_select=
(SQL_SELECT*) join->thd->memdup((uchar*) select, sizeof(SQL_SELECT))))
DBUG_RETURN(1);
cache_select->cond= tmp;
cache_select->read_tables=join->const_table_map;
}
DBUG_RETURN(0);
}
static uint static uint
cache_record_length(JOIN *join,uint idx) cache_record_length(JOIN *join,uint idx)
{ {
...@@ -6751,7 +6793,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -6751,7 +6793,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
COND *const_cond= COND *const_cond=
make_cond_for_table(cond, make_cond_for_table(cond,
join->const_table_map, join->const_table_map,
(table_map) 0, TRUE); (table_map) 0, TRUE, FALSE);
/* Add conditions added by add_not_null_conds(). */ /* Add conditions added by add_not_null_conds(). */
for (uint i= 0 ; i < join->const_tables ; i++) for (uint i= 0 ; i < join->const_tables ; i++)
add_cond_and_fix(&const_cond, join->join_tab[i].select_cond); add_cond_and_fix(&const_cond, join->join_tab[i].select_cond);
...@@ -6765,7 +6807,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -6765,7 +6807,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
JOIN_TAB *cond_tab= tab->first_inner; JOIN_TAB *cond_tab= tab->first_inner;
COND *tmp= make_cond_for_table(*tab->on_expr_ref, COND *tmp= make_cond_for_table(*tab->on_expr_ref,
join->const_table_map, join->const_table_map,
( table_map) 0, FALSE); (table_map) 0, FALSE, FALSE);
if (!tmp) if (!tmp)
continue; continue;
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl); tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
...@@ -6853,7 +6895,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -6853,7 +6895,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tmp= NULL; tmp= NULL;
if (cond) if (cond)
tmp= make_cond_for_table(cond, used_tables, current_map, FALSE); tmp= make_cond_for_table(cond, used_tables, current_map, FALSE, FALSE);
/* Add conditions added by add_not_null_conds(). */ /* Add conditions added by add_not_null_conds(). */
if (tab->select_cond) if (tab->select_cond)
add_cond_and_fix(&tmp, tab->select_cond); add_cond_and_fix(&tmp, tab->select_cond);
...@@ -6912,7 +6954,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -6912,7 +6954,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if (thd->variables.engine_condition_pushdown && !first_inner_tab) if (thd->variables.engine_condition_pushdown && !first_inner_tab)
{ {
COND *push_cond= COND *push_cond=
make_cond_for_table(tmp, current_map, current_map, FALSE); make_cond_for_table(tmp, current_map, current_map, FALSE, FALSE);
if (push_cond) if (push_cond)
{ {
/* Push condition to handler */ /* Push condition to handler */
...@@ -7037,18 +7079,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -7037,18 +7079,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if (i != join->const_tables && tab->use_quick != 2 && if (i != join->const_tables && tab->use_quick != 2 &&
!tab->first_inner) !tab->first_inner)
{ /* Read with cache */ { /* Read with cache */
if (cond && if (tab->make_scan_filter())
(tmp=make_cond_for_table(cond, DBUG_RETURN(1);
join->const_table_map |
current_map,
current_map, FALSE)))
{
DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY););
tab->cache_select=(SQL_SELECT*)
thd->memdup((uchar*) sel, sizeof(SQL_SELECT));
tab->cache_select->cond=tmp;
tab->cache_select->read_tables=join->const_table_map;
}
} }
} }
} }
...@@ -7071,7 +7103,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -7071,7 +7103,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
JOIN_TAB *cond_tab= join_tab->first_inner; JOIN_TAB *cond_tab= join_tab->first_inner;
COND *tmp= make_cond_for_table(*join_tab->on_expr_ref, COND *tmp= make_cond_for_table(*join_tab->on_expr_ref,
join->const_table_map, join->const_table_map,
(table_map) 0, FALSE); (table_map) 0, FALSE, FALSE);
if (!tmp) if (!tmp)
continue; continue;
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl); tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
...@@ -7106,7 +7138,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -7106,7 +7138,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
current_map= tab->table->map; current_map= tab->table->map;
used_tables2|= current_map; used_tables2|= current_map;
COND *tmp_cond= make_cond_for_table(on_expr, used_tables2, COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
current_map, FALSE); current_map, FALSE, FALSE);
add_cond_and_fix(&tmp_cond, tab->on_precond); add_cond_and_fix(&tmp_cond, tab->on_precond);
if (tmp_cond) if (tmp_cond)
{ {
...@@ -7686,7 +7718,8 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7686,7 +7718,8 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if ((cache_level <=4 && !no_hashed_cache) || no_bka_cache || if ((cache_level <=4 && !no_hashed_cache) || no_bka_cache ||
((flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6)) ((flags & HA_MRR_NO_ASSOCIATION) && cache_level <=6))
{ {
if (!tab->hash_join_is_possible()) if (!tab->hash_join_is_possible() ||
tab->make_scan_filter())
goto no_join_cache; goto no_join_cache;
if (cache_level == 3) if (cache_level == 3)
prev_cache= 0; prev_cache= 0;
...@@ -14874,6 +14907,7 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item) ...@@ -14874,6 +14907,7 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item)
used_table Table that we're extracting the condition for (may used_table Table that we're extracting the condition for (may
also include PSEUDO_TABLE_BITS also include PSEUDO_TABLE_BITS
exclude_expensive_cond Do not push expensive conditions exclude_expensive_cond Do not push expensive conditions
retain_ref_cond Retain ref conditions
DESCRIPTION DESCRIPTION
Extract the condition that can be checked after reading the table Extract the condition that can be checked after reading the table
...@@ -14899,16 +14933,18 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item) ...@@ -14899,16 +14933,18 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item)
static Item * static Item *
make_cond_for_table(Item *cond, table_map tables, table_map used_table, make_cond_for_table(Item *cond, table_map tables, table_map used_table,
bool exclude_expensive_cond) bool exclude_expensive_cond, bool retain_ref_cond)
{ {
return make_cond_for_table_from_pred(cond, cond, tables, used_table, return make_cond_for_table_from_pred(cond, cond, tables, used_table,
exclude_expensive_cond); exclude_expensive_cond,
retain_ref_cond);
} }
static Item * static Item *
make_cond_for_table_from_pred(Item *root_cond, Item *cond, make_cond_for_table_from_pred(Item *root_cond, Item *cond,
table_map tables, table_map used_table, table_map tables, table_map used_table,
bool exclude_expensive_cond) bool exclude_expensive_cond,
bool retain_ref_cond)
{ {
if (used_table && !(cond->used_tables() & used_table) && if (used_table && !(cond->used_tables() & used_table) &&
...@@ -14939,7 +14975,8 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond, ...@@ -14939,7 +14975,8 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond,
{ {
Item *fix=make_cond_for_table_from_pred(root_cond, item, Item *fix=make_cond_for_table_from_pred(root_cond, item,
tables, used_table, tables, used_table,
exclude_expensive_cond); exclude_expensive_cond,
retain_ref_cond);
if (fix) if (fix)
new_cond->argument_list()->push_back(fix); new_cond->argument_list()->push_back(fix);
} }
...@@ -14971,7 +15008,8 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond, ...@@ -14971,7 +15008,8 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond,
{ {
Item *fix=make_cond_for_table_from_pred(root_cond, item, Item *fix=make_cond_for_table_from_pred(root_cond, item,
tables, 0L, tables, 0L,
exclude_expensive_cond); exclude_expensive_cond,
retain_ref_cond);
if (!fix) if (!fix)
return (COND*) 0; // Always true return (COND*) 0; // Always true
new_cond->argument_list()->push_back(fix); new_cond->argument_list()->push_back(fix);
...@@ -14992,7 +15030,8 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond, ...@@ -14992,7 +15030,8 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond,
table_count times, we mark each item that we have examined with the result table_count times, we mark each item that we have examined with the result
of the test of the test
*/ */
if (cond->marker == 3 || (cond->used_tables() & ~tables) || if ((cond->marker == 3 && !retain_ref_cond) ||
(cond->used_tables() & ~tables) ||
/* /*
When extracting constant conditions, treat expensive conditions as When extracting constant conditions, treat expensive conditions as
non-constant, so that they are not evaluated at optimization time. non-constant, so that they are not evaluated at optimization time.
...@@ -15007,13 +15046,13 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond, ...@@ -15007,13 +15046,13 @@ make_cond_for_table_from_pred(Item *root_cond, Item *cond,
{ {
Item *left_item= ((Item_func*) cond)->arguments()[0]->real_item(); Item *left_item= ((Item_func*) cond)->arguments()[0]->real_item();
Item *right_item= ((Item_func*) cond)->arguments()[1]->real_item(); Item *right_item= ((Item_func*) cond)->arguments()[1]->real_item();
if (left_item->type() == Item::FIELD_ITEM && if (left_item->type() == Item::FIELD_ITEM && !retain_ref_cond &&
test_if_ref(root_cond, (Item_field*) left_item,right_item)) test_if_ref(root_cond, (Item_field*) left_item,right_item))
{ {
cond->marker=3; // Checked when read cond->marker=3; // Checked when read
return (COND*) 0; return (COND*) 0;
} }
if (right_item->type() == Item::FIELD_ITEM && if (right_item->type() == Item::FIELD_ITEM && !retain_ref_cond &&
test_if_ref(root_cond, (Item_field*) right_item,left_item)) test_if_ref(root_cond, (Item_field*) right_item,left_item))
{ {
cond->marker=3; // Checked when read cond->marker=3; // Checked when read
...@@ -16198,7 +16237,7 @@ static bool fix_having(JOIN *join, Item **having) ...@@ -16198,7 +16237,7 @@ static bool fix_having(JOIN *join, Item **having)
DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY);); DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY););
Item* sort_table_cond=make_cond_for_table(*having, used_tables, used_tables, Item* sort_table_cond=make_cond_for_table(*having, used_tables, used_tables,
FALSE); FALSE, FALSE);
if (sort_table_cond) if (sort_table_cond)
{ {
if (!table->select) if (!table->select)
...@@ -16216,7 +16255,8 @@ static bool fix_having(JOIN *join, Item **having) ...@@ -16216,7 +16255,8 @@ static bool fix_having(JOIN *join, Item **having)
DBUG_EXECUTE("where",print_where(table->select_cond, DBUG_EXECUTE("where",print_where(table->select_cond,
"select and having", "select and having",
QT_ORDINARY);); QT_ORDINARY););
*having= make_cond_for_table(*having,~ (table_map) 0,~used_tables, FALSE); *having= make_cond_for_table(*having,~ (table_map) 0,~used_tables,
FALSE, FALSE);
DBUG_EXECUTE("where", DBUG_EXECUTE("where",
print_where(*having,"having after make_cond", QT_ORDINARY);); print_where(*having,"having after make_cond", QT_ORDINARY););
} }
......
...@@ -394,6 +394,7 @@ typedef struct st_join_table { ...@@ -394,6 +394,7 @@ typedef struct st_join_table {
} }
double get_partial_join_cardinality() { return partial_join_cardinality; } double get_partial_join_cardinality() { return partial_join_cardinality; }
bool hash_join_is_possible(); bool hash_join_is_possible();
int make_scan_filter();
} JOIN_TAB; } JOIN_TAB;
......
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