Commit b77e3dc9 authored by Sergey Petrunya's avatar Sergey Petrunya

MWL#90: Address review feedback part #5

parent 809a8052
......@@ -33,11 +33,11 @@
Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), thd(0), substitution(0),
expr_cache(0), engine(0), old_engine(0), used_tables_cache(0),
have_to_be_excluded(0), const_item_cache(1), inside_first_fix_fields(0),
done_first_fix_fields(FALSE), eliminated(FALSE), engine_changed(0),
changed(0), is_correlated(FALSE)
Item_result_field(), value_assigned(0), thd(0), old_engine(0),
used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1),
inside_first_fix_fields(0), done_first_fix_fields(FALSE),
substitution(0), expr_cache(0), engine(0), eliminated(FALSE),
engine_changed(0), changed(0), is_correlated(FALSE)
{
with_subselect= 1;
reset();
......
......@@ -36,6 +36,22 @@ class Item_subselect :public Item_result_field
protected:
/* thread handler, will be assigned in fix_fields only */
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:
> Item_subselect::fix_fields
......@@ -49,30 +65,12 @@ protected:
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 */
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 */
class Ref_to_outside : public Sql_alloc
{
......@@ -774,61 +772,26 @@ public:
of subselect_single_select_engine::[prepare | cols].
*/
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
temporary table. Created during the first call to exec().
*/
public:
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
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
not equal to the search key in SQL terms.
*/
public:
*/
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_single_select_engine *old_engine)
:subselect_engine(thd, in_predicate, NULL), tmp_table(NULL),
is_materialized(FALSE), materialize_engine(old_engine), lookup_engine(NULL),
materialize_join(NULL), count_partial_match_columns(0),
count_null_only_columns(0), semi_join_conds(NULL), strategy(UNDEFINED)
: subselect_engine(thd, in_predicate, NULL),
tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine),
materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL),
count_partial_match_columns(0), count_null_only_columns(0),
strategy(UNDEFINED)
{}
~subselect_hash_sj_engine();
......@@ -856,6 +819,38 @@ public:
//=>base class
bool change_result(Item_subselect *si, select_result_interceptor *result);
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,
((subselect_hash_sj_engine*)item->engine);
JOIN *join= hash_sj_engine->materialize_join;
double rows= 1;
double read_time= 0.0;
double rows;
double read_time;
/* Calculate #rows and cost of join execution */
for (uint i= join->const_tables; i < join->tables; i++)
{
rows *= join->best_positions[i].records_read;
read_time += join->best_positions[i].read_time;
}
get_partial_join_cost(join, join->tables, &read_time, &rows);
*out_rows= (ha_rows)rows;
*startup_cost= read_time;
/* Calculate cost of scanning the temptable */
......
......@@ -185,6 +185,7 @@ void JOIN_CACHE::calc_record_fields()
start_tab= tab;
if (start_tab->bush_children)
start_tab= start_tab->bush_children->start;
DBUG_ASSERT(!start_tab->bush_children);
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 */
copy= field_descr+flag_fields;
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,
&data_field_count, &copy,
......@@ -721,8 +721,11 @@ ulong JOIN_CACHE::get_min_join_buffer_size()
if (!min_buff_size)
{
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+= get_record_max_affix_length() + get_max_key_addon_space_per_record();
size_t min_sz= len*min_records;
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 min_sz= get_min_join_buffer_size();
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+= get_record_max_affix_length();
avg_record_length= len;
len+= get_max_key_addon_space_per_record() + avg_aux_buffer_incr;
......
......@@ -1035,31 +1035,15 @@ JOIN::optimize()
Perform the optimization on fields evaluation mentioned above
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);
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++))
if (*tab->on_expr_ref)
{
for (JOIN_TAB *tab= jt_range->start + first_tab_offs;
tab < jt_range->end; tab++)
{
if (*tab->on_expr_ref)
{
*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;
*tab->on_expr_ref= substitute_for_best_equal_field(*tab->on_expr_ref,
tab->cond_equal,
map2table);
(*tab->on_expr_ref)->update_used_tables();
}
}
......@@ -1067,47 +1051,34 @@ JOIN::optimize()
Perform the optimization on fields evaliation mentioned above
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;
for (uint i=0; i < tab->ref.key_parts; i++)
{
Item **ref_item_ptr= tab->ref.items+i;
Item *ref_item= *ref_item_ptr;
for (uint i=0; i < tab->ref.key_parts; i++)
{
Item **ref_item_ptr= tab->ref.items+i;
Item *ref_item= *ref_item_ptr;
if (!ref_item->used_tables() && !(select_options & SELECT_DESCRIBE))
continue;
COND_EQUAL *equals= tab->first_inner ? tab->first_inner->cond_equal :
cond_equal;
ref_item= substitute_for_best_equal_field(ref_item, equals, map2table);
ref_item->update_used_tables();
if (*ref_item_ptr != ref_item)
{
*ref_item_ptr= ref_item;
Item *item= ref_item->real_item();
COND_EQUAL *equals= tab->first_inner ? tab->first_inner->cond_equal :
cond_equal;
ref_item= substitute_for_best_equal_field(ref_item, equals, map2table);
ref_item->update_used_tables();
if (*ref_item_ptr != ref_item)
{
*ref_item_ptr= ref_item;
Item *item= ref_item->real_item();
store_key *key_copy= tab->ref.key_copy[key_copy_index];
if (key_copy->type() == store_key::FIELD_STORE_KEY)
{
store_key_field *field_copy= ((store_key_field *)key_copy);
field_copy->change_source_field((Item_field *) item);
}
}
key_copy_index++;
if (key_copy->type() == store_key::FIELD_STORE_KEY)
{
store_key_field *field_copy= ((store_key_field *)key_copy);
field_copy->change_source_field((Item_field *) item);
}
}
first_tab_offs= 0;
key_copy_index++;
}
}
//}
if (conds && const_table_map != found_const_table_map &&
(select_options & SELECT_DESCRIBE))
......@@ -1638,9 +1609,6 @@ bool JOIN::setup_subquery_caches()
for (JOIN_TAB *tab= first_linear_tab(this, TRUE);
tab;
tab= next_linear_tab(this, tab, TRUE))
//for (JOIN_TAB *tab= join_tab + const_tables;
// tab < join_tab + tables ;
// tab++)
{
if (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