Commit d48bec7b authored by Igor Babaev's avatar Igor Babaev

Fixed bug #54539.

Added a possibility not to factor out the condition pushed to
the access index out of the condition pushed to a joined table.
This is useful for the condition pushed to the index when a hashed
join buffer for BKA is employed. In this case the index condition
may be false for some, but for all records with the same key.
So the condition must be checked not only after index lookup,
but after fetching row data as well, and it makes sense not to 
factor out the condition from the condition checked after reading
row data,
The bug happened because the condition pushed to an index always
was factor out from the condition pushed to the accessed table. 
parent ad4271d0
...@@ -4823,7 +4823,7 @@ explain select t2.f1, t2.f2, t2.f3 from t1,t2 ...@@ -4823,7 +4823,7 @@ explain select t2.f1, t2.f2, t2.f3 from t1,t2
where t1.f1=t2.f1 and t2.f2 between t1.f1 and t2.f2; where t1.f1=t2.f1 and t2.f2 between t1.f1 and t2.f2;
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 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ref f1 f1 4 test.t1.f1 3 Using index condition(BKA); Using join buffer 1 SIMPLE t2 ref f1 f1 4 test.t1.f1 3 Using index condition(BKA); Using where; Using join buffer
set join_cache_level=8; set join_cache_level=8;
select t2.f1, t2.f2, t2.f3 from t1,t2 select t2.f1, t2.f2, t2.f3 from t1,t2
where t1.f1=t2.f1 and t2.f2 between t1.f1 and t1.f2 and t2.f2 + 1 >= t1.f1 + 1; where t1.f1=t2.f1 and t2.f2 between t1.f1 and t1.f2 and t2.f2 + 1 >= t1.f1 + 1;
...@@ -4836,7 +4836,7 @@ explain select t2.f1, t2.f2, t2.f3 from t1,t2 ...@@ -4836,7 +4836,7 @@ explain select t2.f1, t2.f2, t2.f3 from t1,t2
where t1.f1=t2.f1 and t2.f2 between t1.f1 and t2.f2; where t1.f1=t2.f1 and t2.f2 between t1.f1 and t2.f2;
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 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ref f1 f1 4 test.t1.f1 3 Using index condition(BKA); Using join buffer 1 SIMPLE t2 ref f1 f1 4 test.t1.f1 3 Using index condition(BKA); Using where; Using join buffer
drop table t1,t2; drop table t1,t2;
set join_cache_level=default; set join_cache_level=default;
# #
...@@ -5303,4 +5303,31 @@ NULL ...@@ -5303,4 +5303,31 @@ NULL
NULL NULL
set join_cache_level = default; set join_cache_level = default;
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# BUG#54359 "Extra rows with join_cache_level=7,8 and two joins
# --and multi-column index"
#
CREATE TABLE t1 (
pk int NOT NULL,
a int DEFAULT NULL,
b varchar(16) DEFAULT NULL,
c varchar(16) DEFAULT NULL,
INDEX idx (b,a))
;
INSERT INTO t1 VALUES (4,9,'k','k');
INSERT INTO t1 VALUES (12,5,'k','k');
set join_cache_level = 8;
EXPLAIN
SELECT t.a FROM t1 t, t1 s FORCE INDEX(idx)
WHERE s.pk AND s.a >= t.pk AND s.b = t.c;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE s ref idx idx 19 test.t.c 1 Using index condition(BKA); Using where; Using join buffer
SELECT t.a FROM t1 t, t1 s FORCE INDEX(idx)
WHERE s.pk AND s.a >= t.pk AND s.b = t.c;
a
9
9
set join_cache_level = default;
DROP TABLE t1;
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -2076,5 +2076,33 @@ SELECT t2.a FROM t1 LEFT JOIN t2 ON t2.b = t1.b; ...@@ -2076,5 +2076,33 @@ SELECT t2.a FROM t1 LEFT JOIN t2 ON t2.b = t1.b;
set join_cache_level = default; set join_cache_level = default;
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # BUG#54359 "Extra rows with join_cache_level=7,8 and two joins
--echo # --and multi-column index"
--echo #
CREATE TABLE t1 (
pk int NOT NULL,
a int DEFAULT NULL,
b varchar(16) DEFAULT NULL,
c varchar(16) DEFAULT NULL,
INDEX idx (b,a))
;
INSERT INTO t1 VALUES (4,9,'k','k');
INSERT INTO t1 VALUES (12,5,'k','k');
set join_cache_level = 8;
EXPLAIN
SELECT t.a FROM t1 t, t1 s FORCE INDEX(idx)
WHERE s.pk AND s.a >= t.pk AND s.b = t.c;
SELECT t.a FROM t1 t, t1 s FORCE INDEX(idx)
WHERE s.pk AND s.a >= t.pk AND s.b = t.c;
set join_cache_level = default;
DROP TABLE t1;
# this must be the last command in the file # this must be the last command in the file
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
...@@ -272,12 +272,14 @@ Item *make_cond_remainder(Item *cond, bool exclude_index) ...@@ -272,12 +272,14 @@ Item *make_cond_remainder(Item *cond, bool exclude_index)
in tab->select_cond in tab->select_cond
keyno Index for which extract and push the condition keyno Index for which extract and push the condition
other_tbls_ok TRUE <=> Fields of other non-const tables are allowed other_tbls_ok TRUE <=> Fields of other non-const tables are allowed
factor_out TRUE <=> Factor out the extracted condition
DESCRIPTION DESCRIPTION
Try to extract and push the index condition down to table handler Try to extract and push the index condition down to table handler
*/ */
void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok) void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok,
bool factor_out)
{ {
DBUG_ENTER("push_index_cond"); DBUG_ENTER("push_index_cond");
Item *idx_cond; Item *idx_cond;
...@@ -350,7 +352,8 @@ void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok) ...@@ -350,7 +352,8 @@ void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok)
if (idx_remainder_cond != idx_cond) if (idx_remainder_cond != idx_cond)
tab->ref.disable_cache= TRUE; tab->ref.disable_cache= TRUE;
Item *row_cond= make_cond_remainder(tab->select_cond, TRUE); Item *row_cond= factor_out ? make_cond_remainder(tab->select_cond, TRUE) :
tab->pre_idx_push_select_cond;
DBUG_EXECUTE("where", DBUG_EXECUTE("where",
print_where(row_cond, "remainder cond", QT_ORDINARY);); print_where(row_cond, "remainder cond", QT_ORDINARY););
......
...@@ -7422,6 +7422,8 @@ end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records) ...@@ -7422,6 +7422,8 @@ end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
no_jbuf_after don't use join buffering after table with this number no_jbuf_after don't use join buffering after table with this number
icp_other_tables_ok OUT TRUE if condition pushdown supports icp_other_tables_ok OUT TRUE if condition pushdown supports
other tables presence other tables presence
idx_cond_fact_out OUT TRUE if condition pushed to the index is factored
out of the condition pushed to the table
DESCRIPTION DESCRIPTION
The function finds out whether the table 'tab' can be joined using a join The function finds out whether the table 'tab' can be joined using a join
...@@ -7545,7 +7547,8 @@ static ...@@ -7545,7 +7547,8 @@ static
uint check_join_cache_usage(JOIN_TAB *tab, uint check_join_cache_usage(JOIN_TAB *tab,
JOIN *join, ulonglong options, JOIN *join, ulonglong options,
uint no_jbuf_after, uint no_jbuf_after,
bool *icp_other_tables_ok) bool *icp_other_tables_ok,
bool *idx_cond_fact_out)
{ {
uint flags; uint flags;
COST_VECT cost; COST_VECT cost;
...@@ -7562,6 +7565,7 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7562,6 +7565,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
uint i= tab - join->join_tab; uint i= tab - join->join_tab;
*icp_other_tables_ok= TRUE; *icp_other_tables_ok= TRUE;
*idx_cond_fact_out= TRUE;
if (cache_level == 0 || i == join->const_tables) if (cache_level == 0 || i == join->const_tables)
return 0; return 0;
...@@ -7665,7 +7669,10 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7665,7 +7669,10 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if ((options & SELECT_DESCRIBE) || if ((options & SELECT_DESCRIBE) ||
((tab->cache= new JOIN_CACHE_BNLH(join, tab, prev_cache)) && ((tab->cache= new JOIN_CACHE_BNLH(join, tab, prev_cache)) &&
!tab->cache->init())) !tab->cache->init()))
{
*icp_other_tables_ok= FALSE;
return (4-test(!prev_cache)); return (4-test(!prev_cache));
}
goto no_join_cache; goto no_join_cache;
} }
if (cache_level > 4 && no_bka_cache) if (cache_level > 4 && no_bka_cache)
...@@ -7694,7 +7701,10 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -7694,7 +7701,10 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if ((options & SELECT_DESCRIBE) || if ((options & SELECT_DESCRIBE) ||
((tab->cache= new JOIN_CACHE_BKAH(join, tab, flags, prev_cache)) && ((tab->cache= new JOIN_CACHE_BKAH(join, tab, flags, prev_cache)) &&
!tab->cache->init())) !tab->cache->init()))
{
*idx_cond_fact_out= FALSE;
return (8-test(!prev_cache)); return (8-test(!prev_cache));
}
goto no_join_cache; goto no_join_cache;
} }
} }
...@@ -7754,6 +7764,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7754,6 +7764,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
JOIN_TAB *tab=join->join_tab+i; JOIN_TAB *tab=join->join_tab+i;
TABLE *table=tab->table; TABLE *table=tab->table;
bool icp_other_tables_ok; bool icp_other_tables_ok;
bool idx_cond_fact_out;
tab->read_record.table= table; tab->read_record.table= table;
tab->read_record.file=table->file; tab->read_record.file=table->file;
tab->read_record.unlock_row= rr_unlock_row; tab->read_record.unlock_row= rr_unlock_row;
...@@ -7800,7 +7811,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7800,7 +7811,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
tab->read_first_record= tab->type == JT_SYSTEM ? tab->read_first_record= tab->type == JT_SYSTEM ?
join_read_system :join_read_const; join_read_system :join_read_const;
if ((jcl= check_join_cache_usage(tab, join, options, if ((jcl= check_join_cache_usage(tab, join, options,
no_jbuf_after, &icp_other_tables_ok))) no_jbuf_after, &icp_other_tables_ok,
&idx_cond_fact_out)))
{ {
tab->use_join_cache= TRUE; tab->use_join_cache= TRUE;
tab[-1].next_select=sub_select_cache; tab[-1].next_select=sub_select_cache;
...@@ -7812,13 +7824,15 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7812,13 +7824,15 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
table->file->extra(HA_EXTRA_KEYREAD); table->file->extra(HA_EXTRA_KEYREAD);
} }
else if (!jcl || jcl > 4) else if (!jcl || jcl > 4)
push_index_cond(tab, tab->ref.key, icp_other_tables_ok); push_index_cond(tab, tab->ref.key,
icp_other_tables_ok, idx_cond_fact_out);
break; break;
case JT_EQ_REF: case JT_EQ_REF:
tab->read_record.unlock_row= join_read_key_unlock_row; tab->read_record.unlock_row= join_read_key_unlock_row;
/* fall through */ /* fall through */
if ((jcl= check_join_cache_usage(tab, join, options, if ((jcl= check_join_cache_usage(tab, join, options,
no_jbuf_after, &icp_other_tables_ok))) no_jbuf_after, &icp_other_tables_ok,
&idx_cond_fact_out)))
{ {
tab->use_join_cache= TRUE; tab->use_join_cache= TRUE;
tab[-1].next_select=sub_select_cache; tab[-1].next_select=sub_select_cache;
...@@ -7830,7 +7844,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7830,7 +7844,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
table->file->extra(HA_EXTRA_KEYREAD); table->file->extra(HA_EXTRA_KEYREAD);
} }
else if (!jcl || jcl > 4) else if (!jcl || jcl > 4)
push_index_cond(tab, tab->ref.key, icp_other_tables_ok ); push_index_cond(tab, tab->ref.key,
icp_other_tables_ok, idx_cond_fact_out);
break; break;
case JT_REF_OR_NULL: case JT_REF_OR_NULL:
case JT_REF: case JT_REF:
...@@ -7842,7 +7857,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7842,7 +7857,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
delete tab->quick; delete tab->quick;
tab->quick=0; tab->quick=0;
if ((jcl= check_join_cache_usage(tab, join, options, if ((jcl= check_join_cache_usage(tab, join, options,
no_jbuf_after, &icp_other_tables_ok))) no_jbuf_after, &icp_other_tables_ok,
&idx_cond_fact_out)))
{ {
tab->use_join_cache= TRUE; tab->use_join_cache= TRUE;
tab[-1].next_select=sub_select_cache; tab[-1].next_select=sub_select_cache;
...@@ -7851,7 +7867,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7851,7 +7867,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
!table->no_keyread) !table->no_keyread)
table->enable_keyread(); table->enable_keyread();
else if (!jcl || jcl > 4) else if (!jcl || jcl > 4)
push_index_cond(tab, tab->ref.key, icp_other_tables_ok); push_index_cond(tab, tab->ref.key,
icp_other_tables_ok, idx_cond_fact_out);
break; break;
case JT_ALL: case JT_ALL:
/* /*
...@@ -7861,7 +7878,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7861,7 +7878,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
materialization nest. materialization nest.
*/ */
if (check_join_cache_usage(tab, join, options, no_jbuf_after, if (check_join_cache_usage(tab, join, options, no_jbuf_after,
&icp_other_tables_ok)) &icp_other_tables_ok, &idx_cond_fact_out))
{ {
tab->use_join_cache= TRUE; tab->use_join_cache= TRUE;
tab[-1].next_select=sub_select_cache; tab[-1].next_select=sub_select_cache;
...@@ -7938,7 +7955,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after) ...@@ -7938,7 +7955,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
} }
if (tab->select && tab->select->quick && if (tab->select && tab->select->quick &&
tab->select->quick->index != MAX_KEY && ! tab->table->key_read) tab->select->quick->index != MAX_KEY && ! tab->table->key_read)
push_index_cond(tab, tab->select->quick->index, icp_other_tables_ok); push_index_cond(tab, tab->select->quick->index,
icp_other_tables_ok, idx_cond_fact_out);
} }
break; break;
case JT_FT: case JT_FT:
......
...@@ -2449,7 +2449,8 @@ inline bool optimizer_flag(THD *thd, uint flag) ...@@ -2449,7 +2449,8 @@ inline bool optimizer_flag(THD *thd, uint flag)
void eliminate_tables(JOIN *join); void eliminate_tables(JOIN *join);
/* Index Condition Pushdown entry point function */ /* Index Condition Pushdown entry point function */
void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok); void push_index_cond(JOIN_TAB *tab, uint keyno, bool other_tbls_ok,
bool factor_out);
/**************************************************************************** /****************************************************************************
Temporary table support for SQL Runtime Temporary table support for SQL Runtime
......
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