Commit 7e34954b authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

new optimisation for ref_null (SCRUM) (WL#818)

parent d9b108c1
...@@ -828,8 +828,21 @@ a t1.a in (select t2.a from t2) ...@@ -828,8 +828,21 @@ a t1.a in (select t2.a from t2)
explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; explain SELECT t1.a, t1.a in (select t2.a from t2) 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 t1 index NULL PRIMARY 4 NULL 4 Using index 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
2 DEPENDENT SUBQUERY t2 index_in a a 5 const 2 Using where; Using index
CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
a t1.a in (select t2.a from t2,t3 where t3.a=t2.a)
1 1
2 1
3 1
4 0
explain SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 const 2 Using where; Using index 2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 const 2 Using where; Using index
drop table t1,t2; 2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where
drop table t1,t2,t3;
create table t1 (a float); create table t1 (a float);
select 10.5 IN (SELECT * from t1 LIMIT 1); select 10.5 IN (SELECT * from t1 LIMIT 1);
ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
......
...@@ -469,7 +469,11 @@ INSERT INTO t1 VALUES (1),(2),(3),(4); ...@@ -469,7 +469,11 @@ INSERT INTO t1 VALUES (1),(2),(3),(4);
INSERT INTO t2 VALUES (1),(2),(3); INSERT INTO t2 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
drop table t1,t2; CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
explain SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
drop table t1,t2,t3;
#LIMIT is not supported now #LIMIT is not supported now
create table t1 (a float); create table t1 (a float);
......
...@@ -669,6 +669,7 @@ public: ...@@ -669,6 +669,7 @@ public:
Item_is_not_null_test(Item_in_subselect* ow, Item *a) Item_is_not_null_test(Item_in_subselect* ow, Item *a)
:Item_func_isnull(a), owner(ow) :Item_func_isnull(a), owner(ow)
{} {}
enum Functype functype() const { return ISNOTNULLTEST_FUNC; }
longlong val_int(); longlong val_int();
const char *func_name() const { return "is_not_null_test"; } const char *func_name() const { return "is_not_null_test"; }
void update_used_tables(); void update_used_tables();
......
...@@ -41,7 +41,7 @@ public: ...@@ -41,7 +41,7 @@ public:
GE_FUNC,GT_FUNC,FT_FUNC, GE_FUNC,GT_FUNC,FT_FUNC,
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC, COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC,
INTERVAL_FUNC, INTERVAL_FUNC, ISNOTNULLTEST_FUNC,
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC, SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC, SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC, SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
......
...@@ -999,8 +999,15 @@ int subselect_indexin_engine::exec() ...@@ -999,8 +999,15 @@ int subselect_indexin_engine::exec()
DBUG_ENTER("subselect_indexin_engine::exec"); DBUG_ENTER("subselect_indexin_engine::exec");
int error; int error;
TABLE *table= tab->table; TABLE *table= tab->table;
((Item_in_subselect *) item)->value= 0; ((Item_in_subselect *) item)->value= 0;
if ((tab->ref.key_err= (*tab->ref.key_copy)->copy())) if (check_null)
{
*tab->null_ref_key= 0;
((Item_in_subselect *) item)->was_null= 0;
}
if ((*tab->ref.key_copy) && (tab->ref.key_err= (*tab->ref.key_copy)->copy()))
{ {
table->status= STATUS_NOT_FOUND; table->status= STATUS_NOT_FOUND;
error= -1; error= -1;
...@@ -1022,12 +1029,21 @@ int subselect_indexin_engine::exec() ...@@ -1022,12 +1029,21 @@ int subselect_indexin_engine::exec()
{ {
if (!cond || cond->val_int()) if (!cond || cond->val_int())
{ {
((Item_in_subselect *) item)->value= 1; if (check_null && *tab->null_ref_key)
((Item_in_subselect *) item)->was_null= 1;
else
((Item_in_subselect *) item)->value= 1;
goto finish; goto finish;
} }
} }
else else
goto finish; {
if (!check_null || *tab->null_ref_key)
goto finish;
*tab->null_ref_key= 1;
if (safe_index_read(tab))
goto finish;
}
error= table->file->index_next_same(table->record[0], error= table->file->index_next_same(table->record[0],
tab->ref.key_buff, tab->ref.key_buff,
tab->ref.key_length); tab->ref.key_length);
......
...@@ -228,6 +228,7 @@ public: ...@@ -228,6 +228,7 @@ public:
friend class Item_asterisk_remover; friend class Item_asterisk_remover;
friend class Item_ref_null_helper; friend class Item_ref_null_helper;
friend class Item_is_not_null_test; friend class Item_is_not_null_test;
friend class subselect_indexin_engine;
}; };
/* ALL/ANY/SOME subselect */ /* ALL/ANY/SOME subselect */
...@@ -337,10 +338,13 @@ public: ...@@ -337,10 +338,13 @@ public:
class subselect_indexin_engine: public subselect_simplein_engine class subselect_indexin_engine: public subselect_simplein_engine
{ {
bool check_null;
public: public:
subselect_indexin_engine(THD *thd, st_join_table *tab_arg, subselect_indexin_engine(THD *thd, st_join_table *tab_arg,
Item_subselect *subs, Item *where) Item_subselect *subs, Item *where,
:subselect_simplein_engine(thd, tab_arg, subs, where) bool chk_null)
:subselect_simplein_engine(thd, tab_arg, subs, where),
check_null(chk_null)
{} {}
int exec(); int exec();
}; };
...@@ -456,7 +456,7 @@ err: ...@@ -456,7 +456,7 @@ err:
bool JOIN::test_in_subselect(Item **where) bool JOIN::test_in_subselect(Item **where)
{ {
if (conds->type() == Item::FUNC_ITEM && if (conds->type() == Item::FUNC_ITEM &&
((class Item_func *)this->conds)->functype() == Item_func::EQ_FUNC && ((Item_func *)this->conds)->functype() == Item_func::EQ_FUNC &&
((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM && ((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM &&
((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM) ((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM)
{ {
...@@ -763,38 +763,57 @@ JOIN::optimize() ...@@ -763,38 +763,57 @@ JOIN::optimize()
/* /*
is this simple IN subquery? is this simple IN subquery?
*/ */
if (!group_list && !order && !having && if (!group_list && !order &&
unit->item && unit->item->substype() == Item_subselect::IN_SUBS && unit->item && unit->item->substype() == Item_subselect::IN_SUBS &&
tables == 1 && conds && tables == 1 && conds &&
!unit->first_select()->next_select()) !unit->first_select()->next_select())
{ {
Item *where= 0; if (!having)
if (join_tab[0].type == JT_EQ_REF)
{ {
if (test_in_subselect(&where)) Item *where= 0;
if (join_tab[0].type == JT_EQ_REF)
{ {
join_tab[0].type= JT_SIMPLE_IN; if (test_in_subselect(&where))
error= 0; {
DBUG_RETURN(unit->item-> join_tab[0].type= JT_SIMPLE_IN;
change_engine(new subselect_simplein_engine(thd, join_tab, error= 0;
unit->item, DBUG_RETURN(unit->item->
where))); change_engine(new subselect_simplein_engine(thd,
join_tab,
unit->item,
where)));
}
} }
} else if (join_tab[0].type == JT_REF)
else if (join_tab[0].type == JT_REF)
{
if (test_in_subselect(&where))
{ {
join_tab[0].type= JT_INDEX_IN; if (test_in_subselect(&where))
error= 0; {
DBUG_RETURN(unit->item-> join_tab[0].type= JT_INDEX_IN;
change_engine(new subselect_indexin_engine(thd, join_tab, error= 0;
unit->item, DBUG_RETURN(unit->item->
where))); change_engine(new subselect_indexin_engine(thd,
join_tab,
unit->item,
where,
0)));
}
} }
} else if (join_tab[0].type == JT_REF_OR_NULL &&
having->type() == Item::FUNC_ITEM &&
((Item_func *) having)->functype() ==
Item_func::ISNOTNULLTEST_FUNC)
{
join_tab[0].type= JT_INDEX_IN;
error= 0;
DBUG_RETURN(unit->item->
change_engine(new subselect_indexin_engine(thd,
join_tab,
unit->item,
conds,
1)));
} }
} }
/* /*
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
...@@ -5445,7 +5464,7 @@ int report_error(TABLE *table, int error) ...@@ -5445,7 +5464,7 @@ int report_error(TABLE *table, int error)
} }
static int safe_index_read(JOIN_TAB *tab) int safe_index_read(JOIN_TAB *tab)
{ {
int error; int error;
TABLE *table= tab->table; TABLE *table= tab->table;
......
...@@ -411,3 +411,4 @@ bool cp_buffer_from_ref(TABLE_REF *ref); ...@@ -411,3 +411,4 @@ 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); int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
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