Commit b77e3dc9 authored by Sergey Petrunya's avatar Sergey Petrunya

MWL#90: Address review feedback part #5

parent 809a8052
...@@ -33,11 +33,11 @@ ...@@ -33,11 +33,11 @@
Item_subselect::Item_subselect(): Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0), Item_result_field(), value_assigned(0), thd(0), old_engine(0),
expr_cache(0), engine(0), old_engine(0), used_tables_cache(0), used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1),
have_to_be_excluded(0), const_item_cache(1), inside_first_fix_fields(0), inside_first_fix_fields(0), done_first_fix_fields(FALSE),
done_first_fix_fields(FALSE), eliminated(FALSE), engine_changed(0), substitution(0), expr_cache(0), engine(0), eliminated(FALSE),
changed(0), is_correlated(FALSE) engine_changed(0), changed(0), is_correlated(FALSE)
{ {
with_subselect= 1; with_subselect= 1;
reset(); reset();
......
...@@ -36,6 +36,22 @@ class Item_subselect :public Item_result_field ...@@ -36,6 +36,22 @@ class Item_subselect :public Item_result_field
protected: protected:
/* thread handler, will be assigned in fix_fields only */ /* thread handler, will be assigned in fix_fields only */
THD *thd; THD *thd;
/* old engine if engine was changed */
subselect_engine *old_engine;
/* cache of used external tables */
table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
/* where subquery is placed */
enum_parsing_place parsing_place;
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constant state */
bool const_item_cache;
bool inside_first_fix_fields;
bool done_first_fix_fields;
public:
/* /*
Used inside Item_subselect::fix_fields() according to this scenario: Used inside Item_subselect::fix_fields() according to this scenario:
> Item_subselect::fix_fields > Item_subselect::fix_fields
...@@ -49,30 +65,12 @@ protected: ...@@ -49,30 +65,12 @@ protected:
substitution= NULL; substitution= NULL;
< Item_subselect::fix_fields < Item_subselect::fix_fields
*/ */
public:
Item *substitution; Item *substitution;
/* unit of subquery */ /* unit of subquery */
st_select_lex_unit *unit; st_select_lex_unit *unit;
Item *expr_cache; Item *expr_cache;
/* engine that perform execution of subselect (single select or union) */ /* engine that perform execution of subselect (single select or union) */
subselect_engine *engine; subselect_engine *engine;
protected:
/* old engine if engine was changed */
subselect_engine *old_engine;
/* cache of used external tables */
table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
/* where subquery is placed */
enum_parsing_place parsing_place;
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constant state */
bool const_item_cache;
bool inside_first_fix_fields;
bool done_first_fix_fields;
public:
/* A reference from inside subquery predicate to somewhere outside of it */ /* A reference from inside subquery predicate to somewhere outside of it */
class Ref_to_outside : public Sql_alloc class Ref_to_outside : public Sql_alloc
{ {
...@@ -774,61 +772,26 @@ public: ...@@ -774,61 +772,26 @@ public:
of subselect_single_select_engine::[prepare | cols]. of subselect_single_select_engine::[prepare | cols].
*/ */
subselect_single_select_engine *materialize_engine; subselect_single_select_engine *materialize_engine;
protected:
/* The engine used to compute the IN predicate. */
subselect_engine *lookup_engine;
/* /*
QEP to execute the subquery and materialize its result into a QEP to execute the subquery and materialize its result into a
temporary table. Created during the first call to exec(). temporary table. Created during the first call to exec().
*/ */
public:
JOIN *materialize_join; JOIN *materialize_join;
protected:
/* Keyparts of the only non-NULL composite index in a rowid merge. */
MY_BITMAP non_null_key_parts;
/* Keyparts of the single column indexes with NULL, one keypart per index. */
MY_BITMAP partial_match_key_parts;
uint count_partial_match_columns;
uint count_null_only_columns;
/* /*
A conjunction of all the equality condtions between all pairs of expressions A conjunction of all the equality condtions between all pairs of expressions
that are arguments of an IN predicate. We need these to post-filter some that are arguments of an IN predicate. We need these to post-filter some
IN results because index lookups sometimes match values that are actually IN results because index lookups sometimes match values that are actually
not equal to the search key in SQL terms. not equal to the search key in SQL terms.
*/ */
public:
Item_cond_and *semi_join_conds; Item_cond_and *semi_join_conds;
protected:
/* Possible execution strategies that can be used to compute hash semi-join.*/
enum exec_strategy {
UNDEFINED,
COMPLETE_MATCH, /* Use regular index lookups. */
PARTIAL_MATCH, /* Use some partial matching strategy. */
PARTIAL_MATCH_MERGE, /* Use partial matching through index merging. */
PARTIAL_MATCH_SCAN, /* Use partial matching through table scan. */
IMPOSSIBLE /* Subquery materialization is not applicable. */
};
/* The chosen execution strategy. Computed after materialization. */
exec_strategy strategy;
protected:
exec_strategy get_strategy_using_schema();
exec_strategy get_strategy_using_data();
ulonglong rowid_merge_buff_size(bool has_non_null_key,
bool has_covering_null_row,
MY_BITMAP *partial_match_key_parts);
void choose_partial_match_strategy(bool has_non_null_key,
bool has_covering_null_row,
MY_BITMAP *partial_match_key_parts);
bool make_semi_join_conds();
subselect_uniquesubquery_engine* make_unique_engine();
public:
subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate, subselect_hash_sj_engine(THD *thd, Item_subselect *in_predicate,
subselect_single_select_engine *old_engine) subselect_single_select_engine *old_engine)
:subselect_engine(thd, in_predicate, NULL), tmp_table(NULL), : subselect_engine(thd, in_predicate, NULL),
is_materialized(FALSE), materialize_engine(old_engine), lookup_engine(NULL), tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine),
materialize_join(NULL), count_partial_match_columns(0), materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL),
count_null_only_columns(0), semi_join_conds(NULL), strategy(UNDEFINED) count_partial_match_columns(0), count_null_only_columns(0),
strategy(UNDEFINED)
{} {}
~subselect_hash_sj_engine(); ~subselect_hash_sj_engine();
...@@ -856,6 +819,38 @@ public: ...@@ -856,6 +819,38 @@ public:
//=>base class //=>base class
bool change_result(Item_subselect *si, select_result_interceptor *result); bool change_result(Item_subselect *si, select_result_interceptor *result);
bool no_tables();//=>base class bool no_tables();//=>base class
protected:
/* The engine used to compute the IN predicate. */
subselect_engine *lookup_engine;
/* Keyparts of the only non-NULL composite index in a rowid merge. */
MY_BITMAP non_null_key_parts;
/* Keyparts of the single column indexes with NULL, one keypart per index. */
MY_BITMAP partial_match_key_parts;
uint count_partial_match_columns;
uint count_null_only_columns;
/* Possible execution strategies that can be used to compute hash semi-join.*/
enum exec_strategy {
UNDEFINED,
COMPLETE_MATCH, /* Use regular index lookups. */
PARTIAL_MATCH, /* Use some partial matching strategy. */
PARTIAL_MATCH_MERGE, /* Use partial matching through index merging. */
PARTIAL_MATCH_SCAN, /* Use partial matching through table scan. */
IMPOSSIBLE /* Subquery materialization is not applicable. */
};
/* The chosen execution strategy. Computed after materialization. */
exec_strategy strategy;
exec_strategy get_strategy_using_schema();
exec_strategy get_strategy_using_data();
ulonglong rowid_merge_buff_size(bool has_non_null_key,
bool has_covering_null_row,
MY_BITMAP *partial_match_key_parts);
void choose_partial_match_strategy(bool has_non_null_key,
bool has_covering_null_row,
MY_BITMAP *partial_match_key_parts);
bool make_semi_join_conds();
subselect_uniquesubquery_engine* make_unique_engine();
}; };
......
...@@ -826,15 +826,12 @@ void get_delayed_table_estimates(TABLE *table, ...@@ -826,15 +826,12 @@ void get_delayed_table_estimates(TABLE *table,
((subselect_hash_sj_engine*)item->engine); ((subselect_hash_sj_engine*)item->engine);
JOIN *join= hash_sj_engine->materialize_join; JOIN *join= hash_sj_engine->materialize_join;
double rows= 1; double rows;
double read_time= 0.0; double read_time;
/* Calculate #rows and cost of join execution */ /* Calculate #rows and cost of join execution */
for (uint i= join->const_tables; i < join->tables; i++) get_partial_join_cost(join, join->tables, &read_time, &rows);
{
rows *= join->best_positions[i].records_read;
read_time += join->best_positions[i].read_time;
}
*out_rows= (ha_rows)rows; *out_rows= (ha_rows)rows;
*startup_cost= read_time; *startup_cost= read_time;
/* Calculate cost of scanning the temptable */ /* Calculate cost of scanning the temptable */
......
...@@ -185,6 +185,7 @@ void JOIN_CACHE::calc_record_fields() ...@@ -185,6 +185,7 @@ void JOIN_CACHE::calc_record_fields()
start_tab= tab; start_tab= tab;
if (start_tab->bush_children) if (start_tab->bush_children)
start_tab= start_tab->bush_children->start; start_tab= start_tab->bush_children->start;
DBUG_ASSERT(!start_tab->bush_children);
tab= start_tab; tab= start_tab;
...@@ -508,7 +509,6 @@ void JOIN_CACHE::create_key_arg_fields() ...@@ -508,7 +509,6 @@ void JOIN_CACHE::create_key_arg_fields()
/* Now create local fields that are used to build ref for this key access */ /* Now create local fields that are used to build ref for this key access */
copy= field_descr+flag_fields; copy= field_descr+flag_fields;
for (tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, FALSE)) for (tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, FALSE))
//for (tab= join_tab-tables; tab; tab= get_next_table(tab))
{ {
length+= add_table_data_fields_to_join_cache(tab, &tab->table->tmp_set, length+= add_table_data_fields_to_join_cache(tab, &tab->table->tmp_set,
&data_field_count, &copy, &data_field_count, &copy,
...@@ -721,8 +721,11 @@ ulong JOIN_CACHE::get_min_join_buffer_size() ...@@ -721,8 +721,11 @@ ulong JOIN_CACHE::get_min_join_buffer_size()
if (!min_buff_size) if (!min_buff_size)
{ {
size_t len= 0; size_t len= 0;
for (JOIN_TAB *tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, FALSE)) for (JOIN_TAB *tab= start_tab; tab != join_tab;
tab= next_linear_tab(join, tab, FALSE))
{
len+= tab->get_max_used_fieldlength(); len+= tab->get_max_used_fieldlength();
}
len+= get_record_max_affix_length() + get_max_key_addon_space_per_record(); len+= get_record_max_affix_length() + get_max_key_addon_space_per_record();
size_t min_sz= len*min_records; size_t min_sz= len*min_records;
size_t add_sz= 0; size_t add_sz= 0;
...@@ -774,8 +777,11 @@ ulong JOIN_CACHE::get_max_join_buffer_size(bool optimize_buff_size) ...@@ -774,8 +777,11 @@ ulong JOIN_CACHE::get_max_join_buffer_size(bool optimize_buff_size)
size_t max_sz; size_t max_sz;
size_t min_sz= get_min_join_buffer_size(); size_t min_sz= get_min_join_buffer_size();
size_t len= 0; size_t len= 0;
for (JOIN_TAB *tab= start_tab; tab != join_tab; tab= next_linear_tab(join, tab, FALSE)) for (JOIN_TAB *tab= start_tab; tab != join_tab;
tab= next_linear_tab(join, tab, FALSE))
{
len+= tab->get_used_fieldlength(); len+= tab->get_used_fieldlength();
}
len+= get_record_max_affix_length(); len+= get_record_max_affix_length();
avg_record_length= len; avg_record_length= len;
len+= get_max_key_addon_space_per_record() + avg_aux_buffer_incr; len+= get_max_key_addon_space_per_record() + avg_aux_buffer_incr;
......
...@@ -1035,31 +1035,15 @@ JOIN::optimize() ...@@ -1035,31 +1035,15 @@ JOIN::optimize()
Perform the optimization on fields evaluation mentioned above Perform the optimization on fields evaluation mentioned above
for all on expressions. for all on expressions.
*/ */
for (JOIN_TAB *tab= first_linear_tab(this, TRUE); tab;
tab= next_linear_tab(this, tab, TRUE))
{ {
List_iterator<JOIN_TAB_RANGE> it(join_tab_ranges); if (*tab->on_expr_ref)
JOIN_TAB_RANGE *jt_range;
/* For upper level JOIN_TABs, we need to skip the const tables: */
uint first_tab_offs= const_tables;
while ((jt_range= it++))
{ {
for (JOIN_TAB *tab= jt_range->start + first_tab_offs; *tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref,
tab < jt_range->end; tab++) tab->cond_equal,
{ map2table);
if (*tab->on_expr_ref) (*tab->on_expr_ref)->update_used_tables();
{
*tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref,
tab->cond_equal,
map2table);
(*tab->on_expr_ref)->update_used_tables();
}
}
/*
Next jt_range will refer to SJM nest (and not the top-level range).
Inside SJM nests, we dont have const tables, so should start from the
first table:
*/
first_tab_offs= 0;
} }
} }
...@@ -1067,47 +1051,34 @@ JOIN::optimize() ...@@ -1067,47 +1051,34 @@ JOIN::optimize()
Perform the optimization on fields evaliation mentioned above Perform the optimization on fields evaliation mentioned above
for all used ref items. for all used ref items.
*/ */
//for (JOIN_TAB *tab= join_tab + const_tables; tab < join_tab + tables; tab++) for (JOIN_TAB *tab= first_linear_tab(this, TRUE); tab;
//{ tab= next_linear_tab(this, tab, TRUE))
{ {
List_iterator<JOIN_TAB_RANGE> it(join_tab_ranges);
JOIN_TAB_RANGE *jt_range;
uint first_tab_offs= const_tables;
while ((jt_range= it++))
{
for (JOIN_TAB *tab= jt_range->start + first_tab_offs;
tab < jt_range->end; tab++)
{
uint key_copy_index=0; uint key_copy_index=0;
for (uint i=0; i < tab->ref.key_parts; i++) for (uint i=0; i < tab->ref.key_parts; i++)
{ {
Item **ref_item_ptr= tab->ref.items+i;
Item **ref_item_ptr= tab->ref.items+i; Item *ref_item= *ref_item_ptr;
Item *ref_item= *ref_item_ptr;
if (!ref_item->used_tables() && !(select_options & SELECT_DESCRIBE)) if (!ref_item->used_tables() && !(select_options & SELECT_DESCRIBE))
continue; continue;
COND_EQUAL *equals= tab->first_inner ? tab->first_inner->cond_equal : COND_EQUAL *equals= tab->first_inner ? tab->first_inner->cond_equal :
cond_equal; cond_equal;
ref_item= substitute_for_best_equal_field(ref_item, equals, map2table); ref_item= substitute_for_best_equal_field(ref_item, equals, map2table);
ref_item->update_used_tables(); ref_item->update_used_tables();
if (*ref_item_ptr != ref_item) if (*ref_item_ptr != ref_item)
{ {
*ref_item_ptr= ref_item; *ref_item_ptr= ref_item;
Item *item= ref_item->real_item(); Item *item= ref_item->real_item();
store_key *key_copy= tab->ref.key_copy[key_copy_index]; store_key *key_copy= tab->ref.key_copy[key_copy_index];
if (key_copy->type() == store_key::FIELD_STORE_KEY) if (key_copy->type() == store_key::FIELD_STORE_KEY)
{ {
store_key_field *field_copy= ((store_key_field *)key_copy); store_key_field *field_copy= ((store_key_field *)key_copy);
field_copy->change_source_field((Item_field *) item); field_copy->change_source_field((Item_field *) item);
}
}
key_copy_index++;
} }
} }
first_tab_offs= 0; key_copy_index++;
} }
} }
//}
if (conds && const_table_map != found_const_table_map && if (conds && const_table_map != found_const_table_map &&
(select_options & SELECT_DESCRIBE)) (select_options & SELECT_DESCRIBE))
...@@ -1638,9 +1609,6 @@ bool JOIN::setup_subquery_caches() ...@@ -1638,9 +1609,6 @@ bool JOIN::setup_subquery_caches()
for (JOIN_TAB *tab= first_linear_tab(this, TRUE); for (JOIN_TAB *tab= first_linear_tab(this, TRUE);
tab; tab;
tab= next_linear_tab(this, tab, TRUE)) tab= next_linear_tab(this, tab, TRUE))
//for (JOIN_TAB *tab= join_tab + const_tables;
// tab < join_tab + tables ;
// tab++)
{ {
if (tab->select_cond) if (tab->select_cond)
tab->select_cond= tab->select_cond=
......
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