Commit dd21ecf5 authored by Sergey Petrunya's avatar Sergey Petrunya

Subquery optimizations: non-semijoin materialization

- Backport into Maria DB 5.3, part 1
parent c2206d6f
...@@ -878,6 +878,9 @@ class Item { ...@@ -878,6 +878,9 @@ class Item {
static CHARSET_INFO *default_charset(); static CHARSET_INFO *default_charset();
virtual CHARSET_INFO *compare_collation() { return NULL; } virtual CHARSET_INFO *compare_collation() { return NULL; }
/* Cache of the result of is_expensive(). */
int8 is_expensive_cache;
virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg) virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{ {
return (this->*processor)(arg); return (this->*processor)(arg);
...@@ -1081,6 +1084,29 @@ class Item { ...@@ -1081,6 +1084,29 @@ class Item {
*/ */
virtual bool result_as_longlong() { return FALSE; } virtual bool result_as_longlong() { return FALSE; }
bool is_datetime(); bool is_datetime();
/*
Test whether an expression is expensive to compute. Used during
optimization to avoid computing expensive expressions during this
phase. Also used to force temp tables when sorting on expensive
functions.
TODO:
Normally we should have a method:
cost Item::execution_cost(),
where 'cost' is either 'double' or some structure of various cost
parameters.
NOTE
This function is now used to prevent evaluation of materialized IN
subquery predicates before it is allowed. grep for
DontEvaluateMaterializedSubqueryTooEarly to see the uses.
*/
virtual bool is_expensive()
{
if (is_expensive_cache < 0)
is_expensive_cache= walk(&Item::is_expensive_processor, 0, (uchar*)0);
return test(is_expensive_cache);
}
virtual Field::geometry_type get_geometry_type() const virtual Field::geometry_type get_geometry_type() const
{ return Field::GEOM_GEOMETRY; }; { return Field::GEOM_GEOMETRY; };
String *check_well_formed_result(String *str, bool send_error= 0); String *check_well_formed_result(String *str, bool send_error= 0);
...@@ -2842,9 +2868,10 @@ class Cached_item_field :public Cached_item ...@@ -2842,9 +2868,10 @@ class Cached_item_field :public Cached_item
uint length; uint length;
public: public:
Cached_item_field(Item_field *item) Cached_item_field(Field *arg_field) : field(arg_field)
{ {
field= item->field; field= arg_field;
/* TODO: take the memory allocation below out of the constructor. */
buff= (uchar*) sql_calloc(length=field->pack_length()); buff= (uchar*) sql_calloc(length=field->pack_length());
} }
bool cmp(void); bool cmp(void);
...@@ -3271,7 +3298,8 @@ void mark_select_range_as_dependent(THD *thd, ...@@ -3271,7 +3298,8 @@ void mark_select_range_as_dependent(THD *thd,
Field *found_field, Item *found_item, Field *found_field, Item *found_item,
Item_ident *resolved_item); Item_ident *resolved_item);
extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Cached_item *new_Cached_item(THD *thd, Item *item,
bool use_result_field);
extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item_result item_cmp_type(Item_result a,Item_result b);
extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
extern int stored_field_cmp_to_item(Field *field, Item *item); extern int stored_field_cmp_to_item(Field *field, Item *item);
...@@ -27,11 +27,16 @@ ...@@ -27,11 +27,16 @@
Create right type of Cached_item for an item. Create right type of Cached_item for an item.
*/ */
Cached_item *new_Cached_item(THD *thd, Item *item) Cached_item *new_Cached_item(THD *thd, Item *item, bool use_result_field)
{ {
if (item->real_item()->type() == Item::FIELD_ITEM && if (item->real_item()->type() == Item::FIELD_ITEM &&
!(((Item_field *) (item->real_item()))->field->flags & BLOB_FLAG)) !(((Item_field *) (item->real_item()))->field->flags & BLOB_FLAG))
return new Cached_item_field((Item_field *) (item->real_item())); {
Item_field *real_item= (Item_field *) item->real_item();
Field *cached_field= use_result_field ? real_item->result_field :
real_item->field;
return new Cached_item_field(cached_field);
}
switch (item->result_type()) { switch (item->result_type()) {
case STRING_RESULT: case STRING_RESULT:
return new Cached_item_str(thd, (Item_field *) item); return new Cached_item_str(thd, (Item_field *) item);
......
...@@ -490,12 +490,12 @@ Field *Item_func::tmp_table_field(TABLE *table) ...@@ -490,12 +490,12 @@ Field *Item_func::tmp_table_field(TABLE *table)
return field; return field;
} }
/*
bool Item_func::is_expensive_processor(uchar *arg) bool Item_func::is_expensive_processor(uchar *arg)
{ {
return is_expensive(); return is_expensive();
} }
*/
my_decimal *Item_func::val_decimal(my_decimal *decimal_value) my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
{ {
......
...@@ -192,8 +192,8 @@ class Item_func :public Item_result_field ...@@ -192,8 +192,8 @@ class Item_func :public Item_result_field
Item_transformer transformer, uchar *arg_t); Item_transformer transformer, uchar *arg_t);
void traverse_cond(Cond_traverser traverser, void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order); void * arg, traverse_order order);
bool is_expensive_processor(uchar *arg); // bool is_expensive_processor(uchar *arg);
virtual bool is_expensive() { return 0; } // virtual bool is_expensive() { return 0; }
inline double fix_result(double value) inline double fix_result(double value)
{ {
if (isfinite(value)) if (isfinite(value))
...@@ -1053,6 +1053,7 @@ class Item_udf_func :public Item_func ...@@ -1053,6 +1053,7 @@ class Item_udf_func :public Item_func
{ {
protected: protected:
udf_handler udf; udf_handler udf;
bool is_expensive_processor(uchar *arg) { return TRUE; }
public: public:
Item_udf_func(udf_func *udf_arg) Item_udf_func(udf_func *udf_arg)
...@@ -1677,6 +1678,9 @@ class Item_func_sp :public Item_func ...@@ -1677,6 +1678,9 @@ class Item_func_sp :public Item_func
bool execute_impl(THD *thd); bool execute_impl(THD *thd);
bool init_result_field(THD *thd); bool init_result_field(THD *thd);
protected:
bool is_expensive_processor(uchar *arg) { return TRUE; }
public: public:
Item_func_sp(Name_resolution_context *context_arg, sp_name *name); Item_func_sp(Name_resolution_context *context_arg, sp_name *name);
......
This diff is collapsed.
This diff is collapsed.
...@@ -5493,7 +5493,7 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) ...@@ -5493,7 +5493,7 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
DBUG_RETURN(tree); DBUG_RETURN(tree);
} }
/* Here when simple cond */ /* Here when simple cond */
if (cond->const_item()) if (cond->const_item() && !cond->is_expensive())
{ {
/* /*
During the cond->val_int() evaluation we can come across a subselect During the cond->val_int() evaluation we can come across a subselect
......
...@@ -2076,16 +2076,28 @@ void st_select_lex::print_limit(THD *thd, ...@@ -2076,16 +2076,28 @@ void st_select_lex::print_limit(THD *thd,
{ {
SELECT_LEX_UNIT *unit= master_unit(); SELECT_LEX_UNIT *unit= master_unit();
Item_subselect *item= unit->item; Item_subselect *item= unit->item;
if (item && unit->global_parameters == this &&
(item->substype() == Item_subselect::EXISTS_SUBS || if (item && unit->global_parameters == this)
item->substype() == Item_subselect::IN_SUBS || {
item->substype() == Item_subselect::ALL_SUBS)) Item_subselect::subs_type subs_type= item->substype();
if (subs_type == Item_subselect::EXISTS_SUBS ||
subs_type == Item_subselect::IN_SUBS ||
subs_type == Item_subselect::ALL_SUBS)
{ {
DBUG_ASSERT(!item->fixed || DBUG_ASSERT(!item->fixed ||
(select_limit->val_int() == LL(1) && offset_limit == 0)); /*
If not using materialization both:
select_limit == 1, and there should be no offset_limit.
*/
(((subs_type == Item_subselect::IN_SUBS) &&
((Item_in_subselect*)item)->exec_method ==
Item_in_subselect::MATERIALIZATION) ?
TRUE :
(select_limit->val_int() == 1LL) &&
offset_limit == 0));
return; return;
} }
}
if (explicit_limit) if (explicit_limit)
{ {
str->append(STRING_WITH_LEN(" limit ")); str->append(STRING_WITH_LEN(" limit "));
...@@ -2098,6 +2110,7 @@ void st_select_lex::print_limit(THD *thd, ...@@ -2098,6 +2110,7 @@ void st_select_lex::print_limit(THD *thd,
} }
} }
/** /**
@brief Restore the LEX and THD in case of a parse error. @brief Restore the LEX and THD in case of a parse error.
......
...@@ -559,7 +559,8 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -559,7 +559,8 @@ class st_select_lex_unit: public st_select_lex_node {
bool add_fake_select_lex(THD *thd); bool add_fake_select_lex(THD *thd);
void init_prepare_fake_select_lex(THD *thd); void init_prepare_fake_select_lex(THD *thd);
inline bool is_prepared() { return prepared; } inline bool is_prepared() { return prepared; }
bool change_result(select_subselect *result, select_subselect *old_result); bool change_result(select_result_interceptor *result,
select_result_interceptor *old_result);
void set_limit(st_select_lex *values); void set_limit(st_select_lex *values);
void set_thd(THD *thd_arg) { thd= thd_arg; } void set_thd(THD *thd_arg) { thd= thd_arg; }
inline bool is_union (); inline bool is_union ();
......
This diff is collapsed.
...@@ -1199,6 +1199,14 @@ enum_nested_loop_state sub_select_sjm(JOIN *join, JOIN_TAB *join_tab, ...@@ -1199,6 +1199,14 @@ enum_nested_loop_state sub_select_sjm(JOIN *join, JOIN_TAB *join_tab,
bool end_of_records); bool end_of_records);
int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl); int do_sj_dups_weedout(THD *thd, SJ_TMP_TABLE *sjtbl);
enum_nested_loop_state
end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records);
enum_nested_loop_state
end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
bool end_of_records);
/** /**
Information about a position of table within a join order. Used in join Information about a position of table within a join order. Used in join
optimization. optimization.
...@@ -1945,6 +1953,7 @@ bool error_if_full_join(JOIN *join); ...@@ -1945,6 +1953,7 @@ bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error); int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab); int safe_index_read(JOIN_TAB *tab);
COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value); COND *remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value);
int test_if_item_cache_changed(List<Cached_item> &list);
void calc_used_field_length(THD *thd, JOIN_TAB *join_tab); void calc_used_field_length(THD *thd, JOIN_TAB *join_tab);
int join_init_read_record(JOIN_TAB *tab); int join_init_read_record(JOIN_TAB *tab);
void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key); void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key);
......
...@@ -715,8 +715,8 @@ void st_select_lex_unit::reinit_exec_mechanism() ...@@ -715,8 +715,8 @@ void st_select_lex_unit::reinit_exec_mechanism()
TRUE - error TRUE - error
*/ */
bool st_select_lex_unit::change_result(select_subselect *new_result, bool st_select_lex_unit::change_result(select_result_interceptor *new_result,
select_subselect *old_result) select_result_interceptor *old_result)
{ {
bool res= FALSE; bool res= FALSE;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
......
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