Commit 6ac8e9b9 authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

optimisation of independent ALL/ANY with aggregate function (WL#1115) (SCRUM)

parent c06786fa
......@@ -1347,4 +1347,13 @@ explain select * from t3 where a >= all (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
insert into t2 values (2,2), (2,1), (3,3), (3,1);
select * from t3 where a > all (select max(b) from t2 group by a);
a
6
7
explain select * from t3 where a > all (select max(b) from t2 group by a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort
drop table if exists t2, t3;
......@@ -877,6 +877,7 @@ insert into t1 values (1);
insert into t2 values (1);
select * from t1 where exists (select s1 from t2 having max(t2.s1)=t1.s1);
drop table t1,t2;
#
# update subquery with wrong field (to force name resolving
# in UPDATE name space)
......@@ -897,4 +898,9 @@ create table t3 (a int);
insert into t3 values (6),(7),(3);
select * from t3 where a >= all (select b from t2);
explain select * from t3 where a >= all (select b from t2);
# optimized static ALL/ANY with grouping
insert into t2 values (2,2), (2,1), (3,3), (3,1);
select * from t3 where a > all (select max(b) from t2 group by a);
explain select * from t3 where a > all (select max(b) from t2 group by a);
drop table if exists t2, t3;
......@@ -152,8 +152,8 @@ inline table_map Item_subselect::used_tables() const
}
Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect(), value(0)
st_select_lex *select_lex)
:Item_subselect(), value(0)
{
DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect");
init(thd, select_lex, new select_singlerow_subselect(this));
......@@ -163,6 +163,19 @@ Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
DBUG_VOID_RETURN;
}
Item_maxmin_subselect::Item_maxmin_subselect(THD *thd,
st_select_lex *select_lex,
bool max)
:Item_singlerow_subselect()
{
DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect");
init(thd, select_lex, new select_max_min_finder_subselect(this, max));
max_columns= 1;
maybe_null= 1;
max_columns= 1;
DBUG_VOID_RETURN;
}
void Item_singlerow_subselect::reset()
{
null_value= 1;
......@@ -499,38 +512,50 @@ Item_in_subselect::single_value_transformer(JOIN *join,
(func == &Item_bool_func2::gt_creator ||
func == &Item_bool_func2::lt_creator ||
func == &Item_bool_func2::ge_creator ||
func == &Item_bool_func2::le_creator) &&
!select_lex->group_list.elements &&
!select_lex->with_sum_func)
func == &Item_bool_func2::le_creator))
{
Item *item;
subs_type type= substype();
if (func == &Item_bool_func2::le_creator ||
func == &Item_bool_func2::lt_creator)
Item *subs;
if (!select_lex->group_list.elements &&
!select_lex->with_sum_func)
{
/*
(ALL && (> || =>)) || (ANY && (< || =<))
for ALL condition is inverted
*/
item= new Item_sum_max(*select_lex->ref_pointer_array);
Item *item;
subs_type type= substype();
if (func == &Item_bool_func2::le_creator ||
func == &Item_bool_func2::lt_creator)
{
/*
(ALL && (> || =>)) || (ANY && (< || =<))
for ALL condition is inverted
*/
item= new Item_sum_max(*select_lex->ref_pointer_array);
}
else
{
/*
(ALL && (< || =<)) || (ANY && (> || =>))
for ALL condition is inverted
*/
item= new Item_sum_min(*select_lex->ref_pointer_array);
}
*select_lex->ref_pointer_array= item;
select_lex->item_list.empty();
select_lex->item_list.push_back(item);
if (item->fix_fields(thd, join->tables_list, &item))
{
DBUG_RETURN(ERROR);
}
subs= new Item_singlerow_subselect(thd, select_lex);
}
else
{
/*
(ALL && (< || =<)) || (ANY && (> || =>))
for ALL condition is inverted
*/
item= new Item_sum_min(*select_lex->ref_pointer_array);
}
*select_lex->ref_pointer_array= item;
select_lex->item_list.empty();
select_lex->item_list.push_back(item);
if (item->fix_fields(thd, join->tables_list, &item))
{
DBUG_RETURN(ERROR);
// remove LIMIT placed by ALL/ANY subquery
select_lex->master_unit()->global_parameters->select_limit=
HA_POS_ERROR;
subs= new Item_maxmin_subselect(thd, select_lex,
(func == &Item_bool_func2::le_creator ||
func == &Item_bool_func2::lt_creator));
}
// left expression belong to outer select
SELECT_LEX *current= thd->lex.current_select, *up;
thd->lex.current_select= up= current->return_after_parsing();
......@@ -540,8 +565,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
DBUG_RETURN(ERROR);
}
thd->lex.current_select= current;
substitution= (*func)(left_expr,
new Item_singlerow_subselect(thd, select_lex));
substitution= (*func)(left_expr, subs);
DBUG_RETURN(OK);
}
......
......@@ -130,6 +130,7 @@ class Item_singlerow_subselect :public Item_subselect
max_length= item->max_length;
decimals= item->decimals;
}
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
subs_type substype() { return SINGLEROW_SUBS; }
......@@ -153,6 +154,15 @@ class Item_singlerow_subselect :public Item_subselect
friend class select_singlerow_subselect;
};
/* used in static ALL/ANY optimisation */
class Item_maxmin_subselect: public Item_singlerow_subselect
{
public:
Item_maxmin_subselect(THD *thd, st_select_lex *select_lex, bool max);
Item_maxmin_subselect(Item_maxmin_subselect *item)
:Item_singlerow_subselect(item) {}
};
/* exists subselect */
class Item_exists_subselect :public Item_subselect
......
......@@ -986,6 +986,95 @@ bool select_singlerow_subselect::send_data(List<Item> &items)
DBUG_RETURN(0);
}
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_max_min_finder_subselect::send_data");
Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
List_iterator_fast<Item> li(items);
Item *val_item= li++;
if (it->assigned())
{
cache->store(val_item);
if ((this->*op)())
it->store(0, cache);
}
else
{
if (!cache)
{
cache= Item_cache::get_cache(val_item->result_type());
switch (val_item->result_type())
{
case REAL_RESULT:
op= &select_max_min_finder_subselect::cmp_real;
break;
case INT_RESULT:
op= &select_max_min_finder_subselect::cmp_int;
break;
case STRING_RESULT:
op= &select_max_min_finder_subselect::cmp_str;
break;
case ROW_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
op= 0;
}
}
cache->store(val_item);
it->store(0, cache);
}
it->assigned(1);
DBUG_RETURN(0);
}
bool select_max_min_finder_subselect::cmp_real()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
double val1= cache->val(), val2= maxmin->val();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 > val2);
else
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 < val2);
}
bool select_max_min_finder_subselect::cmp_int()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
longlong val1= cache->val_int(), val2= maxmin->val_int();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 > val2);
else
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
val1 < val2);
}
bool select_max_min_finder_subselect::cmp_str()
{
String *val1, *val2, buf1, buf2;
Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
/*
as far as both operand is Item_cache buf1 & buf2 will not be used,
but added for safety
*/
val1= cache->val_str(&buf1);
val2= maxmin->val_str(&buf1);
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value &&
sortcmp(val1, val2, cache->collation.collation) > 0) ;
else
return (maxmin->null_value && !cache->null_value) ||
(!cache->null_value && !maxmin->null_value &&
sortcmp(val1, val2, cache->collation.collation) < 0);
}
bool select_exists_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_exists_subselect::send_data");
......
......@@ -920,6 +920,22 @@ class select_singlerow_subselect :public select_subselect
bool send_data(List<Item> &items);
};
/* used in independent ALL/ANY optimisation */
class select_max_min_finder_subselect :public select_subselect
{
Item_cache *cache;
bool (select_max_min_finder_subselect::*op)();
bool fmax;
public:
select_max_min_finder_subselect(Item_subselect *item, bool mx)
:select_subselect(item), cache(0), fmax(mx)
{}
bool send_data(List<Item> &items);
bool cmp_real();
bool cmp_int();
bool cmp_str();
};
/* EXISTS subselect interface class */
class select_exists_subselect :public select_subselect
{
......
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