mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +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
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
|
||||||
2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found
|
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;
|
drop table if exists t2, t3;
|
||||||
|
@ -877,6 +877,7 @@ insert into t1 values (1);
|
|||||||
insert into t2 values (1);
|
insert into t2 values (1);
|
||||||
select * from t1 where exists (select s1 from t2 having max(t2.s1)=t1.s1);
|
select * from t1 where exists (select s1 from t2 having max(t2.s1)=t1.s1);
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
|
||||||
#
|
#
|
||||||
# update subquery with wrong field (to force name resolving
|
# update subquery with wrong field (to force name resolving
|
||||||
# in UPDATE name space)
|
# in UPDATE name space)
|
||||||
@ -897,4 +898,9 @@ create table t3 (a int);
|
|||||||
insert into t3 values (6),(7),(3);
|
insert into t3 values (6),(7),(3);
|
||||||
select * from t3 where a >= all (select b from t2);
|
select * from t3 where a >= all (select b from t2);
|
||||||
explain 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;
|
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,
|
Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
|
||||||
st_select_lex *select_lex):
|
st_select_lex *select_lex)
|
||||||
Item_subselect(), value(0)
|
:Item_subselect(), value(0)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect");
|
DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect");
|
||||||
init(thd, select_lex, new select_singlerow_subselect(this));
|
init(thd, select_lex, new select_singlerow_subselect(this));
|
||||||
@ -163,6 +163,19 @@ Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
|
|||||||
DBUG_VOID_RETURN;
|
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()
|
void Item_singlerow_subselect::reset()
|
||||||
{
|
{
|
||||||
null_value= 1;
|
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::gt_creator ||
|
||||||
func == &Item_bool_func2::lt_creator ||
|
func == &Item_bool_func2::lt_creator ||
|
||||||
func == &Item_bool_func2::ge_creator ||
|
func == &Item_bool_func2::ge_creator ||
|
||||||
func == &Item_bool_func2::le_creator) &&
|
func == &Item_bool_func2::le_creator))
|
||||||
!select_lex->group_list.elements &&
|
|
||||||
!select_lex->with_sum_func)
|
|
||||||
{
|
{
|
||||||
Item *item;
|
Item *subs;
|
||||||
subs_type type= substype();
|
if (!select_lex->group_list.elements &&
|
||||||
if (func == &Item_bool_func2::le_creator ||
|
!select_lex->with_sum_func)
|
||||||
func == &Item_bool_func2::lt_creator)
|
|
||||||
{
|
{
|
||||||
/*
|
Item *item;
|
||||||
(ALL && (> || =>)) || (ANY && (< || =<))
|
subs_type type= substype();
|
||||||
for ALL condition is inverted
|
if (func == &Item_bool_func2::le_creator ||
|
||||||
*/
|
func == &Item_bool_func2::lt_creator)
|
||||||
item= new Item_sum_max(*select_lex->ref_pointer_array);
|
{
|
||||||
|
/*
|
||||||
|
(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
|
else
|
||||||
{
|
{
|
||||||
/*
|
// remove LIMIT placed by ALL/ANY subquery
|
||||||
(ALL && (< || =<)) || (ANY && (> || =>))
|
select_lex->master_unit()->global_parameters->select_limit=
|
||||||
for ALL condition is inverted
|
HA_POS_ERROR;
|
||||||
*/
|
subs= new Item_maxmin_subselect(thd, select_lex,
|
||||||
item= new Item_sum_min(*select_lex->ref_pointer_array);
|
(func == &Item_bool_func2::le_creator ||
|
||||||
|
func == &Item_bool_func2::lt_creator));
|
||||||
}
|
}
|
||||||
*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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// left expression belong to outer select
|
// left expression belong to outer select
|
||||||
SELECT_LEX *current= thd->lex.current_select, *up;
|
SELECT_LEX *current= thd->lex.current_select, *up;
|
||||||
thd->lex.current_select= up= current->return_after_parsing();
|
thd->lex.current_select= up= current->return_after_parsing();
|
||||||
@ -540,8 +565,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
|
|||||||
DBUG_RETURN(ERROR);
|
DBUG_RETURN(ERROR);
|
||||||
}
|
}
|
||||||
thd->lex.current_select= current;
|
thd->lex.current_select= current;
|
||||||
substitution= (*func)(left_expr,
|
substitution= (*func)(left_expr, subs);
|
||||||
new Item_singlerow_subselect(thd, select_lex));
|
|
||||||
DBUG_RETURN(OK);
|
DBUG_RETURN(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +130,7 @@ public:
|
|||||||
max_length= item->max_length;
|
max_length= item->max_length;
|
||||||
decimals= item->decimals;
|
decimals= item->decimals;
|
||||||
}
|
}
|
||||||
|
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
|
||||||
|
|
||||||
subs_type substype() { return SINGLEROW_SUBS; }
|
subs_type substype() { return SINGLEROW_SUBS; }
|
||||||
|
|
||||||
@ -153,6 +154,15 @@ public:
|
|||||||
friend class select_singlerow_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 */
|
/* exists subselect */
|
||||||
|
|
||||||
class Item_exists_subselect :public Item_subselect
|
class Item_exists_subselect :public Item_subselect
|
||||||
|
@ -986,6 +986,95 @@ bool select_singlerow_subselect::send_data(List<Item> &items)
|
|||||||
DBUG_RETURN(0);
|
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)
|
bool select_exists_subselect::send_data(List<Item> &items)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("select_exists_subselect::send_data");
|
DBUG_ENTER("select_exists_subselect::send_data");
|
||||||
|
@ -920,6 +920,22 @@ public:
|
|||||||
bool send_data(List<Item> &items);
|
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 */
|
/* EXISTS subselect interface class */
|
||||||
class select_exists_subselect :public select_subselect
|
class select_exists_subselect :public select_subselect
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user