Commit 06b048f0 authored by unknown's avatar unknown

new IN subquery engine added for simple IN with non-primary index but without NULL returning

(SCRUM) (part of WL#818)


mysql-test/r/subselect.result:
  test of new engine
mysql-test/t/subselect.test:
  test of new engine
sql/item_subselect.cc:
  new engine added
  some common operation moved in separate method
sql/item_subselect.h:
  new engine added
  some common operation moved in separate method
sql/sql_select.cc:
  new engine added
  some common operation moved in separate method
sql/sql_select.h:
  some common operation moved in separate method
parent 21afeb48
...@@ -1245,7 +1245,7 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -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 ...@@ -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 ...@@ -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); ...@@ -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); ...@@ -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,8 +972,13 @@ int subselect_simplein_engine::exec() ...@@ -972,8 +972,13 @@ 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 tmp= 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))) if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
{ {
DBUG_PRINT("error", ("extra(HA_EXTRA_NO_CACHE) failed")); DBUG_PRINT("error", ("extra(HA_EXTRA_NO_CACHE) failed"));
...@@ -986,8 +991,56 @@ int subselect_simplein_engine::exec() ...@@ -986,8 +991,56 @@ int subselect_simplein_engine::exec()
} }
if (error == 1) if (error == 1)
table->file->print_error(tmp, MYF(0)); 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;
}
}
}
} }
DBUG_RETURN(error != 0) finish:
DBUG_RETURN(end_exec(table) || (error != 0));
} }
uint subselect_single_select_engine::cols() uint subselect_single_select_engine::cols()
......
...@@ -184,6 +184,7 @@ class Item_exists_subselect :public Item_subselect ...@@ -184,6 +184,7 @@ class Item_exists_subselect :public Item_subselect
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 @@ class subselect_union_engine: public subselect_engine ...@@ -314,6 +315,7 @@ class subselect_union_engine: public subselect_engine
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 @@ class subselect_simplein_engine: public subselect_engine ...@@ -330,4 +332,15 @@ class subselect_simplein_engine: public subselect_engine
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 @@ ...@@ -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 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -440,6 +440,42 @@ JOIN::prepare(Item ***rref_pointer_array,
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,30 +765,13 @@ JOIN::optimize() ...@@ -729,30 +765,13 @@ 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";
}
else if (conds->type() == Item::COND_ITEM &&
((class Item_func *)this->conds)->functype() ==
Item_func::COND_AND_FUNC)
{
ok= 1;
where= conds;
join_tab->info= "Using index; Using where";
}
if (ok)
{ {
join_tab[0].type= JT_SIMPLE_IN; join_tab[0].type= JT_SIMPLE_IN;
error= 0; error= 0;
...@@ -762,6 +781,19 @@ JOIN::optimize() ...@@ -762,6 +781,19 @@ JOIN::optimize()
where))); where)));
} }
} }
else if (join_tab[0].type == JT_REF)
{
if (test_in_subselect(&where))
{
join_tab[0].type= JT_INDEX_IN;
error= 0;
DBUG_RETURN(unit->item->
change_engine(new subselect_indexin_engine(thd, join_tab,
unit->item,
where)));
}
}
}
/* /*
Need to tell Innobase that to play it safe, it should fetch all Need to tell Innobase that to play it safe, it should fetch all
......
...@@ -76,7 +76,7 @@ typedef struct st_join_cache { ...@@ -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 ...@@ -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);
}; };
......
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