Commit 6348e63f authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

Optimisation if simple IN subselect with primary index

(SCRUM) (part of WL#818)
parent 7ad53317
...@@ -1226,7 +1226,15 @@ a ...@@ -1226,7 +1226,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 PRIMARY 4 NULL 4 Using where; Using index 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index 2 DEPENDENT SUBQUERY t1 simple_in PRIMARY PRIMARY 4 func 1 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 PRIMARY 4 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 simple_in PRIMARY PRIMARY 4 func 1 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
......
...@@ -819,6 +819,8 @@ insert into t2 values (2), (3), (4), (5); ...@@ -819,6 +819,8 @@ 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);
drop table t1, t2, t3; drop table t1, t2, t3;
......
...@@ -36,7 +36,7 @@ inline Item * and_items(Item* cond, Item *item) ...@@ -36,7 +36,7 @@ inline Item * and_items(Item* cond, Item *item)
Item_subselect::Item_subselect(): Item_subselect::Item_subselect():
Item_result_field(), engine_owner(1), value_assigned(0), substitution(0), Item_result_field(), engine_owner(1), value_assigned(0), substitution(0),
have_to_be_excluded(0) have_to_be_excluded(0), engine_changed(0)
{ {
reset(); reset();
/* /*
...@@ -117,16 +117,22 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) ...@@ -117,16 +117,22 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
bool Item_subselect::exec() bool Item_subselect::exec()
{ {
int res;
MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC); MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
if (&thd->mem_root != old_root) if (&thd->mem_root != old_root)
{ {
my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root); my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root);
int res= engine->exec(); res= engine->exec();
my_pthread_setspecific_ptr(THR_MALLOC, old_root); my_pthread_setspecific_ptr(THR_MALLOC, old_root);
return (res);
} }
else else
return engine->exec(); res= engine->exec();
if (engine_changed)
{
engine_changed= 0;
return exec();
}
return (res);
} }
Item::Type Item_subselect::type() const Item::Type Item_subselect::type() const
...@@ -795,6 +801,13 @@ int subselect_union_engine::prepare() ...@@ -795,6 +801,13 @@ int subselect_union_engine::prepare()
return unit->prepare(thd, result, 0); return unit->prepare(thd, result, 0);
} }
int subselect_simplein_engine::prepare()
{
//this never should be called
DBUG_ASSERT(0);
return 1;
}
static Item_result set_row(SELECT_LEX *select_lex, Item * item, static Item_result set_row(SELECT_LEX *select_lex, Item * item,
Item_cache **row, bool *maybe_null) Item_cache **row, bool *maybe_null)
{ {
...@@ -873,6 +886,12 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) ...@@ -873,6 +886,12 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
} }
} }
void subselect_simplein_engine::fix_length_and_dec(Item_cache **row)
{
//this never should be called
DBUG_ASSERT(0);
}
int subselect_single_select_engine::exec() int subselect_single_select_engine::exec()
{ {
DBUG_ENTER("subselect_single_select_engine::exec"); DBUG_ENTER("subselect_single_select_engine::exec");
...@@ -889,6 +908,10 @@ int subselect_single_select_engine::exec() ...@@ -889,6 +908,10 @@ int subselect_single_select_engine::exec()
join->thd->lex.current_select= save_select; join->thd->lex.current_select= save_select;
DBUG_RETURN(join->error?join->error:1); DBUG_RETURN(join->error?join->error:1);
} }
if (item->engine_changed)
{
DBUG_RETURN(1);
}
} }
if ((select_lex->dependent || select_lex->uncacheable) && executed) if ((select_lex->dependent || select_lex->uncacheable) && executed)
{ {
...@@ -922,6 +945,51 @@ int subselect_union_engine::exec() ...@@ -922,6 +945,51 @@ int subselect_union_engine::exec()
return res; return res;
} }
int subselect_simplein_engine::exec()
{
DBUG_ENTER("subselect_simplein_engine::exec");
int error;
TABLE *table= tab->table;
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
{
error= 0;
table->null_row= 0;
if (table->status)
((Item_in_subselect *) item)->value= 0;
else
((Item_in_subselect *) item)->value= (!cond || cond->val_int()?1:0);
}
}
{
int tmp= 0;
if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
{
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)
}
uint subselect_single_select_engine::cols() uint subselect_single_select_engine::cols()
{ {
return select_lex->item_list.elements; return select_lex->item_list.elements;
...@@ -961,3 +1029,9 @@ void subselect_union_engine::exclude() ...@@ -961,3 +1029,9 @@ void subselect_union_engine::exclude()
{ {
unit->exclude_level(); unit->exclude_level();
} }
void subselect_simplein_engine::exclude()
{
//this never should be called
DBUG_ASSERT(0);
}
...@@ -48,7 +48,12 @@ class Item_subselect :public Item_result_field ...@@ -48,7 +48,12 @@ class Item_subselect :public Item_result_field
bool have_to_be_excluded; bool have_to_be_excluded;
public: public:
/* changed engine indicator */
bool engine_changed;
enum trans_res {OK, REDUCE, ERROR}; enum trans_res {OK, REDUCE, ERROR};
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
EXISTS_SUBS, IN_SUBS, ALLANY_SUBS};
Item_subselect(); Item_subselect();
Item_subselect(Item_subselect *item) Item_subselect(Item_subselect *item)
...@@ -59,9 +64,12 @@ class Item_subselect :public Item_result_field ...@@ -59,9 +64,12 @@ class Item_subselect :public Item_result_field
max_columns= item->max_columns; max_columns= item->max_columns;
engine= item->engine; engine= item->engine;
engine_owner= 0; engine_owner= 0;
engine_changed= item->engine_changed;
name= item->name; name= item->name;
} }
virtual subs_type substype() { return UNKNOWN_SUBS; }
/* /*
We need this method, because some compilers do not allow 'this' We need this method, because some compilers do not allow 'this'
pointer in constructor initialization list, but we need pass pointer pointer in constructor initialization list, but we need pass pointer
...@@ -95,6 +103,12 @@ class Item_subselect :public Item_result_field ...@@ -95,6 +103,12 @@ class Item_subselect :public Item_result_field
else else
str->append("-subselect-"); str->append("-subselect-");
} }
bool change_engine(subselect_engine *eng)
{
engine= eng;
engine_changed= 1;
return eng == 0;
}
friend class select_subselect; friend class select_subselect;
friend class Item_in_optimizer; friend class Item_in_optimizer;
...@@ -116,6 +130,9 @@ class Item_singlerow_subselect :public Item_subselect ...@@ -116,6 +130,9 @@ class Item_singlerow_subselect :public Item_subselect
max_length= item->max_length; max_length= item->max_length;
decimals= item->decimals; decimals= item->decimals;
} }
subs_type substype() { return SINGLEROW_SUBS; }
void reset(); void reset();
trans_res select_transformer(JOIN *join); trans_res select_transformer(JOIN *join);
void store(uint i, Item* item); void store(uint i, Item* item);
...@@ -152,6 +169,7 @@ class Item_exists_subselect :public Item_subselect ...@@ -152,6 +169,7 @@ class Item_exists_subselect :public Item_subselect
} }
Item_exists_subselect(): Item_subselect() {} Item_exists_subselect(): Item_subselect() {}
subs_type substype() { return EXISTS_SUBS; }
void reset() void reset()
{ {
value= 0; value= 0;
...@@ -165,6 +183,7 @@ class Item_exists_subselect :public Item_subselect ...@@ -165,6 +183,7 @@ class Item_exists_subselect :public Item_subselect
void fix_length_and_dec(); void fix_length_and_dec();
friend class select_exists_subselect; friend class select_exists_subselect;
friend class subselect_simplein_engine;
}; };
/* IN subselect */ /* IN subselect */
...@@ -185,6 +204,8 @@ class Item_in_subselect :public Item_exists_subselect ...@@ -185,6 +204,8 @@ class Item_in_subselect :public Item_exists_subselect
Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex); Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
Item_in_subselect(Item_in_subselect *item); Item_in_subselect(Item_in_subselect *item);
Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {} Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {}
subs_type substype() { return IN_SUBS; }
void reset() void reset()
{ {
value= 0; value= 0;
...@@ -218,6 +239,7 @@ class Item_allany_subselect :public Item_in_subselect ...@@ -218,6 +239,7 @@ class Item_allany_subselect :public Item_in_subselect
Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f, Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f,
st_select_lex *select_lex); st_select_lex *select_lex);
Item_allany_subselect(Item_allany_subselect *item); Item_allany_subselect(Item_allany_subselect *item);
subs_type substype() { return ALLANY_SUBS; }
trans_res select_transformer(JOIN *join); trans_res select_transformer(JOIN *join);
}; };
...@@ -288,3 +310,24 @@ class subselect_union_engine: public subselect_engine ...@@ -288,3 +310,24 @@ class subselect_union_engine: public subselect_engine
bool uncacheable(); bool uncacheable();
void exclude(); void exclude();
}; };
struct st_join_table;
class subselect_simplein_engine: public subselect_engine
{
st_join_table *tab;
Item *cond;
public:
subselect_simplein_engine(THD *thd, st_join_table *tab_arg,
Item_subselect *subs, Item *where)
:subselect_engine(thd, subs, 0), tab(tab_arg), cond(where)
{}
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
uint cols() { return 1; }
bool dependent() { return 1; }
bool uncacheable() { return 1; }
void exclude();
};
...@@ -283,7 +283,7 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -283,7 +283,7 @@ class st_select_lex_unit: public st_select_lex_node {
st_select_lex *return_to; st_select_lex *return_to;
/* LIMIT clause runtime counters */ /* LIMIT clause runtime counters */
ha_rows select_limit_cnt, offset_limit_cnt; ha_rows select_limit_cnt, offset_limit_cnt;
/* not NULL if union used in subselect, point to subselect item */ /* not NULL if unit used in subselect, point to subselect item */
Item_subselect *item; Item_subselect *item;
/* thread handler */ /* thread handler */
THD *thd; THD *thd;
......
...@@ -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" "ref_or_null","simple_in"
}; };
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
...@@ -723,6 +723,45 @@ JOIN::optimize() ...@@ -723,6 +723,45 @@ JOIN::optimize()
(select_lex->ftfunc_list->elements ? (select_lex->ftfunc_list->elements ?
SELECT_NO_JOIN_CACHE : 0)); SELECT_NO_JOIN_CACHE : 0));
/*
is this simple IN subquery?
*/
if (!group_list && !order && !having &&
unit->item && unit->item->substype() == Item_subselect::IN_SUBS &&
tables == 1 && join_tab[0].type == JT_EQ_REF &&
conds &&
!unit->first_select()->next_select())
{
Item *where= 0;
bool ok= 0;
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;
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;
error= 0;
DBUG_RETURN(unit->item->
change_engine(new subselect_simplein_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
columns of the tables: this is because MySQL may build row columns of the tables: this is because MySQL may build row
...@@ -5337,7 +5376,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last) ...@@ -5337,7 +5376,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
/* Help function when we get some an error from the table handler */ /* Help function when we get some an error from the table handler */
static int report_error(TABLE *table, int error) int report_error(TABLE *table, int error)
{ {
if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND) if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND)
{ {
......
...@@ -75,7 +75,8 @@ typedef struct st_join_cache { ...@@ -75,7 +75,8 @@ 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};
class JOIN; class JOIN;
...@@ -305,7 +306,6 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, ...@@ -305,7 +306,6 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
/* functions from opt_sum.cc */ /* functions from opt_sum.cc */
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds); int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
/* class to copying an field/item to a key struct */ /* class to copying an field/item to a key struct */
class store_key :public Sql_alloc class store_key :public Sql_alloc
...@@ -407,3 +407,4 @@ class store_key_const_item :public store_key_item ...@@ -407,3 +407,4 @@ class store_key_const_item :public store_key_item
bool cp_buffer_from_ref(TABLE_REF *ref); bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join); bool error_if_full_join(JOIN *join);
void relink_tables(SELECT_LEX *select_lex); void relink_tables(SELECT_LEX *select_lex);
int report_error(TABLE *table, int error);
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