new IN subquery engine added for simple IN with non-primary index but without NULL returning
(SCRUM) (part of WL#818)
This commit is contained in:
parent
acece34bce
commit
8279740af4
@ -1245,7 +1245,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||||||
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where
|
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where
|
||||||
2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index
|
2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index
|
||||||
drop table t1, t2, t3;
|
drop table t1, t2, t3;
|
||||||
create table t1 (a int, b int, index a (a));
|
create table t1 (a int, b int, index a (a,b));
|
||||||
create table t2 (a int, index a (a));
|
create table t2 (a int, index a (a));
|
||||||
create table t3 (a int, b int, index a (a));
|
create table t3 (a int, b int, index a (a));
|
||||||
insert into t1 values (1,10), (2,20), (3,30), (4,40);
|
insert into t1 values (1,10), (2,20), (3,30), (4,40);
|
||||||
@ -1259,7 +1259,15 @@ a
|
|||||||
explain select * from t2 where t2.a in (select a from t1);
|
explain select * from t2 where t2.a in (select a from t1);
|
||||||
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 t2 index NULL a 5 NULL 4 Using where; Using index
|
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
|
||||||
2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where; Using index
|
2 DEPENDENT SUBQUERY t1 index_in a a 5 func 100 Using index
|
||||||
|
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
|
a
|
||||||
|
2
|
||||||
|
4
|
||||||
|
explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
|
||||||
|
2 DEPENDENT SUBQUERY t1 index_in a a 5 func 100 Using index; Using where
|
||||||
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||||
a
|
a
|
||||||
2
|
2
|
||||||
@ -1267,8 +1275,22 @@ a
|
|||||||
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||||
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 t2 index NULL a 5 NULL 4 Using where; Using index
|
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
|
||||||
2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where
|
2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using index
|
||||||
2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index
|
2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 100 Using where; Using index
|
||||||
|
insert into t1 values (3,31);
|
||||||
|
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
|
a
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31);
|
||||||
|
a
|
||||||
|
2
|
||||||
|
4
|
||||||
|
explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
|
||||||
|
2 DEPENDENT SUBQUERY t1 index_in a a 5 func 100 Using index; Using where
|
||||||
drop table t1, t2, t3;
|
drop table t1, t2, t3;
|
||||||
create table t1 (a int, b int);
|
create table t1 (a int, b int);
|
||||||
create table t2 (a int, b int);
|
create table t2 (a int, b int);
|
||||||
|
@ -824,7 +824,7 @@ explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
|||||||
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||||
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||||
drop table t1, t2, t3;
|
drop table t1, t2, t3;
|
||||||
create table t1 (a int, b int, index a (a));
|
create table t1 (a int, b int, index a (a,b));
|
||||||
create table t2 (a int, index a (a));
|
create table t2 (a int, index a (a));
|
||||||
create table t3 (a int, b int, index a (a));
|
create table t3 (a int, b int, index a (a));
|
||||||
insert into t1 values (1,10), (2,20), (3,30), (4,40);
|
insert into t1 values (1,10), (2,20), (3,30), (4,40);
|
||||||
@ -841,8 +841,14 @@ insert into t2 values (2), (3), (4), (5);
|
|||||||
insert into t3 values (10,3), (20,4), (30,5);
|
insert into t3 values (10,3), (20,4), (30,5);
|
||||||
select * from t2 where t2.a in (select a from t1);
|
select * from t2 where t2.a in (select a from t1);
|
||||||
explain select * from t2 where t2.a in (select a from t1);
|
explain select * from t2 where t2.a in (select a from t1);
|
||||||
|
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
|
explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||||
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
|
||||||
|
insert into t1 values (3,31);
|
||||||
|
select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
|
select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31);
|
||||||
|
explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
|
||||||
drop table t1, t2, t3;
|
drop table t1, t2, t3;
|
||||||
#
|
#
|
||||||
# alloc_group_fields() working
|
# alloc_group_fields() working
|
||||||
|
@ -972,22 +972,75 @@ int subselect_simplein_engine::exec()
|
|||||||
((Item_in_subselect *) item)->value= (!cond || cond->val_int()?1:0);
|
((Item_in_subselect *) item)->value= (!cond || cond->val_int()?1:0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBUG_RETURN(end_exec(table) || (error != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int subselect_simplein_engine::end_exec(TABLE *table)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("subselect_simplein_engine::end_exec");
|
||||||
|
int error=0, tmp;
|
||||||
|
if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
|
||||||
{
|
{
|
||||||
int tmp= 0;
|
DBUG_PRINT("error", ("extra(HA_EXTRA_NO_CACHE) failed"));
|
||||||
if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
|
error= 1;
|
||||||
{
|
|
||||||
DBUG_PRINT("error", ("extra(HA_EXTRA_NO_CACHE) failed"));
|
|
||||||
error= 1;
|
|
||||||
}
|
|
||||||
if ((tmp= table->file->index_end()))
|
|
||||||
{
|
|
||||||
DBUG_PRINT("error", ("index_end() failed"));
|
|
||||||
error= 1;
|
|
||||||
}
|
|
||||||
if (error == 1)
|
|
||||||
table->file->print_error(tmp, MYF(0));
|
|
||||||
}
|
}
|
||||||
DBUG_RETURN(error != 0)
|
if ((tmp= table->file->index_end()))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("error", ("index_end() failed"));
|
||||||
|
error= 1;
|
||||||
|
}
|
||||||
|
if (error == 1)
|
||||||
|
table->file->print_error(tmp, MYF(0));
|
||||||
|
DBUG_RETURN(error != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int subselect_indexin_engine::exec()
|
||||||
|
{
|
||||||
|
DBUG_ENTER("subselect_indexin_engine::exec");
|
||||||
|
int error;
|
||||||
|
TABLE *table= tab->table;
|
||||||
|
((Item_in_subselect *) item)->value= 0;
|
||||||
|
if ((tab->ref.key_err= (*tab->ref.key_copy)->copy()))
|
||||||
|
{
|
||||||
|
table->status= STATUS_NOT_FOUND;
|
||||||
|
error= -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error= table->file->index_read(table->record[0],
|
||||||
|
tab->ref.key_buff,
|
||||||
|
tab->ref.key_length,HA_READ_KEY_EXACT);
|
||||||
|
if (error && error != HA_ERR_KEY_NOT_FOUND)
|
||||||
|
error= report_error(table, error);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
error= 0;
|
||||||
|
table->null_row= 0;
|
||||||
|
if (!table->status)
|
||||||
|
{
|
||||||
|
if (!cond || cond->val_int())
|
||||||
|
{
|
||||||
|
((Item_in_subselect *) item)->value= 1;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto finish;
|
||||||
|
error= table->file->index_next_same(table->record[0],
|
||||||
|
tab->ref.key_buff,
|
||||||
|
tab->ref.key_length);
|
||||||
|
if (error && error != HA_ERR_KEY_NOT_FOUND)
|
||||||
|
{
|
||||||
|
error= report_error(table, error);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finish:
|
||||||
|
DBUG_RETURN(end_exec(table) || (error != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint subselect_single_select_engine::cols()
|
uint subselect_single_select_engine::cols()
|
||||||
|
@ -184,6 +184,7 @@ public:
|
|||||||
|
|
||||||
friend class select_exists_subselect;
|
friend class select_exists_subselect;
|
||||||
friend class subselect_simplein_engine;
|
friend class subselect_simplein_engine;
|
||||||
|
friend class subselect_indexin_engine;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* IN subselect */
|
/* IN subselect */
|
||||||
@ -314,6 +315,7 @@ public:
|
|||||||
struct st_join_table;
|
struct st_join_table;
|
||||||
class subselect_simplein_engine: public subselect_engine
|
class subselect_simplein_engine: public subselect_engine
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
st_join_table *tab;
|
st_join_table *tab;
|
||||||
Item *cond;
|
Item *cond;
|
||||||
public:
|
public:
|
||||||
@ -330,4 +332,15 @@ public:
|
|||||||
bool dependent() { return 1; }
|
bool dependent() { return 1; }
|
||||||
bool uncacheable() { return 1; }
|
bool uncacheable() { return 1; }
|
||||||
void exclude();
|
void exclude();
|
||||||
|
static int end_exec(TABLE *table);
|
||||||
|
};
|
||||||
|
|
||||||
|
class subselect_indexin_engine: public subselect_simplein_engine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
subselect_indexin_engine(THD *thd, st_join_table *tab_arg,
|
||||||
|
Item_subselect *subs, Item *where)
|
||||||
|
:subselect_simplein_engine(thd, tab_arg, subs, where)
|
||||||
|
{}
|
||||||
|
int exec();
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
|
||||||
"MAYBE_REF","ALL","range","index","fulltext",
|
"MAYBE_REF","ALL","range","index","fulltext",
|
||||||
"ref_or_null","simple_in"
|
"ref_or_null","simple_in","index_in"
|
||||||
};
|
};
|
||||||
|
|
||||||
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
||||||
@ -440,6 +440,42 @@ err:
|
|||||||
DBUG_RETURN(-1); /* purecov: inspected */
|
DBUG_RETURN(-1); /* purecov: inspected */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
test if it is known for optimisation IN subquery
|
||||||
|
|
||||||
|
SYNOPSYS
|
||||||
|
JOIN::test_in_subselect
|
||||||
|
where - pointer for variable in which conditions should be
|
||||||
|
stored if subquery is known
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
1 - known
|
||||||
|
0 - unknown
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool JOIN::test_in_subselect(Item **where)
|
||||||
|
{
|
||||||
|
if (conds->type() == Item::FUNC_ITEM &&
|
||||||
|
((class Item_func *)this->conds)->functype() == Item_func::EQ_FUNC &&
|
||||||
|
((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM &&
|
||||||
|
((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM)
|
||||||
|
{
|
||||||
|
join_tab->info= "Using index";
|
||||||
|
*where= 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (conds->type() == Item::COND_ITEM &&
|
||||||
|
((class Item_func *)this->conds)->functype() ==
|
||||||
|
Item_func::COND_AND_FUNC)
|
||||||
|
{
|
||||||
|
*where= conds;
|
||||||
|
join_tab->info= "Using index; Using where";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
global select optimisation.
|
global select optimisation.
|
||||||
return 0 - success
|
return 0 - success
|
||||||
@ -729,37 +765,33 @@ JOIN::optimize()
|
|||||||
*/
|
*/
|
||||||
if (!group_list && !order && !having &&
|
if (!group_list && !order && !having &&
|
||||||
unit->item && unit->item->substype() == Item_subselect::IN_SUBS &&
|
unit->item && unit->item->substype() == Item_subselect::IN_SUBS &&
|
||||||
tables == 1 && join_tab[0].type == JT_EQ_REF &&
|
tables == 1 && conds &&
|
||||||
conds &&
|
|
||||||
!unit->first_select()->next_select())
|
!unit->first_select()->next_select())
|
||||||
{
|
{
|
||||||
Item *where= 0;
|
Item *where= 0;
|
||||||
bool ok= 0;
|
if (join_tab[0].type == JT_EQ_REF)
|
||||||
if (conds->type() == Item::FUNC_ITEM &&
|
|
||||||
((class Item_func *)this->conds)->functype() == Item_func::EQ_FUNC &&
|
|
||||||
((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM &&
|
|
||||||
((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM)
|
|
||||||
{
|
{
|
||||||
ok= 1;
|
if (test_in_subselect(&where))
|
||||||
join_tab->info= "Using index";
|
{
|
||||||
|
join_tab[0].type= JT_SIMPLE_IN;
|
||||||
|
error= 0;
|
||||||
|
DBUG_RETURN(unit->item->
|
||||||
|
change_engine(new subselect_simplein_engine(thd, join_tab,
|
||||||
|
unit->item,
|
||||||
|
where)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (conds->type() == Item::COND_ITEM &&
|
else if (join_tab[0].type == JT_REF)
|
||||||
((class Item_func *)this->conds)->functype() ==
|
|
||||||
Item_func::COND_AND_FUNC)
|
|
||||||
{
|
{
|
||||||
ok= 1;
|
if (test_in_subselect(&where))
|
||||||
where= conds;
|
{
|
||||||
join_tab->info= "Using index; Using where";
|
join_tab[0].type= JT_INDEX_IN;
|
||||||
}
|
error= 0;
|
||||||
|
DBUG_RETURN(unit->item->
|
||||||
if (ok)
|
change_engine(new subselect_indexin_engine(thd, join_tab,
|
||||||
{
|
unit->item,
|
||||||
join_tab[0].type= JT_SIMPLE_IN;
|
where)));
|
||||||
error= 0;
|
}
|
||||||
DBUG_RETURN(unit->item->
|
|
||||||
change_engine(new subselect_simplein_engine(thd, join_tab,
|
|
||||||
unit->item,
|
|
||||||
where)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ typedef struct st_join_cache {
|
|||||||
|
|
||||||
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
|
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
|
||||||
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
|
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
|
||||||
JT_SIMPLE_IN};
|
JT_SIMPLE_IN, JT_INDEX_IN};
|
||||||
|
|
||||||
class JOIN;
|
class JOIN;
|
||||||
|
|
||||||
@ -277,7 +277,8 @@ class JOIN :public Sql_alloc
|
|||||||
bool rollup_init();
|
bool rollup_init();
|
||||||
bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
|
bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
|
||||||
Item_sum ***func);
|
Item_sum ***func);
|
||||||
int JOIN::rollup_send_data(uint idx);
|
int rollup_send_data(uint idx);
|
||||||
|
bool test_in_subselect(Item **where);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user