mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
optimisation of independent ALL/ANY with aggregate function (WL#1115) (SCRUM)
This commit is contained in:
@ -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,8 +512,10 @@ 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 &&
|
||||
func == &Item_bool_func2::le_creator))
|
||||
{
|
||||
Item *subs;
|
||||
if (!select_lex->group_list.elements &&
|
||||
!select_lex->with_sum_func)
|
||||
{
|
||||
Item *item;
|
||||
@ -530,7 +545,17 @@ Item_in_subselect::single_value_transformer(JOIN *join,
|
||||
{
|
||||
DBUG_RETURN(ERROR);
|
||||
}
|
||||
|
||||
subs= new Item_singlerow_subselect(thd, select_lex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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
|
||||
{
|
||||
|
Reference in New Issue
Block a user