MWL#90: Address review feedback part #5

This commit is contained in:
Sergey Petrunya 2011-03-22 13:09:55 +03:00
parent 809a805251
commit b77e3dc9f4
5 changed files with 101 additions and 135 deletions

View File

@ -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();

View File

@ -36,27 +36,6 @@ 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;
/*
Used inside Item_subselect::fix_fields() according to this scenario:
> Item_subselect::fix_fields
> engine->prepare
> child_join->prepare
(Here we realize we need to do the rewrite and set
substitution= some new Item, eg. Item_in_optimizer )
< child_join->prepare
< engine->prepare
*ref= substitution;
substitution= NULL;
< Item_subselect::fix_fields
*/
public:
Item *substitution;
/* unit of subquery */
st_select_lex_unit *unit;
Item *expr_cache;
/* engine that perform execution of subselect (single select or union) */
subselect_engine *engine;
protected:
/* old engine if engine was changed */ /* old engine if engine was changed */
subselect_engine *old_engine; subselect_engine *old_engine;
/* cache of used external tables */ /* cache of used external tables */
@ -73,6 +52,25 @@ protected:
bool inside_first_fix_fields; bool inside_first_fix_fields;
bool done_first_fix_fields; bool done_first_fix_fields;
public: public:
/*
Used inside Item_subselect::fix_fields() according to this scenario:
> Item_subselect::fix_fields
> engine->prepare
> child_join->prepare
(Here we realize we need to do the rewrite and set
substitution= some new Item, eg. Item_in_optimizer )
< child_join->prepare
< engine->prepare
*ref= substitution;
substitution= NULL;
< Item_subselect::fix_fields
*/
Item *substitution;
/* unit of subquery */
st_select_lex_unit *unit;
Item *expr_cache;
/* engine that perform execution of subselect (single select or union) */
subselect_engine *engine;
/* 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:
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:
//=>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();
}; };

View File

@ -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 */

View File

@ -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()
/* 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()
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)
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;

View File

@ -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()
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()
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=