mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
MDEV-17493: Partition pruning doesn't work for nested outer joins
Reuse the fix for MDEV-17518 here, too.
This commit is contained in:
parent
03680a9b4f
commit
3b6d903852
4 changed files with 120 additions and 61 deletions
|
@ -3484,3 +3484,36 @@ select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) O
|
|||
a b c d
|
||||
1 a b 1
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-17493: Partition pruning doesn't work for nested outer joins
|
||||
#
|
||||
create table t0(a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, c int);
|
||||
insert into t1 select a,a,a from t0;
|
||||
create table t2 (a int, b int, c int);
|
||||
insert into t2 select a,a,a from t0;
|
||||
create table t3 (
|
||||
part_id int,
|
||||
a int
|
||||
) partition by list (part_id) (
|
||||
partition p0 values in (0),
|
||||
partition p1 values in (1),
|
||||
partition p2 values in (2),
|
||||
partition p3 values in (3),
|
||||
partition p4 values in (4)
|
||||
);
|
||||
insert into t3 select mod(a,5), a from t0;
|
||||
explain partitions
|
||||
select * from t1 left join t3 on (t1.a=t3.a and t3.part_id=3);
|
||||
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 10
|
||||
1 SIMPLE t3 p3 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
|
||||
# The following should have partitions="p3", NOT p0,p1,p2,p3,p4:
|
||||
explain partitions
|
||||
select * from t1 left join (t3 join t2) on (t1.a=t3.a and t3.a=t2.b and t3.part_id=3);
|
||||
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 10
|
||||
1 SIMPLE t3 p3 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
|
||||
1 SIMPLE t2 NULL ALL NULL NULL NULL NULL 10 Using where; Using join buffer (incremental, BNL join)
|
||||
drop table t0,t1,t2,t3;
|
||||
|
|
|
@ -1535,4 +1535,35 @@ select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) O
|
|||
(a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2))));
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-17493: Partition pruning doesn't work for nested outer joins
|
||||
--echo #
|
||||
|
||||
create table t0(a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
create table t1 (a int, b int, c int);
|
||||
insert into t1 select a,a,a from t0;
|
||||
create table t2 (a int, b int, c int);
|
||||
insert into t2 select a,a,a from t0;
|
||||
|
||||
create table t3 (
|
||||
part_id int,
|
||||
a int
|
||||
) partition by list (part_id) (
|
||||
partition p0 values in (0),
|
||||
partition p1 values in (1),
|
||||
partition p2 values in (2),
|
||||
partition p3 values in (3),
|
||||
partition p4 values in (4)
|
||||
);
|
||||
insert into t3 select mod(a,5), a from t0;
|
||||
|
||||
explain partitions
|
||||
select * from t1 left join t3 on (t1.a=t3.a and t3.part_id=3);
|
||||
|
||||
--echo # The following should have partitions="p3", NOT p0,p1,p2,p3,p4:
|
||||
explain partitions
|
||||
select * from t1 left join (t3 join t2) on (t1.a=t3.a and t3.a=t2.b and t3.part_id=3);
|
||||
|
||||
drop table t0,t1,t2,t3;
|
||||
|
||||
|
|
|
@ -292,6 +292,9 @@ static bool find_order_in_list(THD *, Ref_ptr_array, TABLE_LIST *, ORDER *,
|
|||
static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
|
||||
table_map rem_tables);
|
||||
void set_postjoin_aggr_write_func(JOIN_TAB *tab);
|
||||
|
||||
static Item **get_sargable_cond(JOIN *join, TABLE *table);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
|
||||
/*
|
||||
|
@ -1770,19 +1773,9 @@ JOIN::optimize_inner()
|
|||
List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
|
||||
while ((tbl= li++))
|
||||
{
|
||||
/*
|
||||
If tbl->embedding!=NULL that means that this table is in the inner
|
||||
part of the nested outer join, and we can't do partition pruning
|
||||
(TODO: check if this limitation can be lifted)
|
||||
*/
|
||||
if (!tbl->embedding ||
|
||||
(tbl->embedding && tbl->embedding->sj_on_expr))
|
||||
{
|
||||
Item *prune_cond= tbl->on_expr? tbl->on_expr : conds;
|
||||
tbl->table->all_partitions_pruned_away= prune_partitions(thd,
|
||||
tbl->table,
|
||||
prune_cond);
|
||||
}
|
||||
Item **prune_cond= get_sargable_cond(this, tbl->table);
|
||||
tbl->table->all_partitions_pruned_away=
|
||||
prune_partitions(thd, tbl->table, *prune_cond);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -4334,6 +4327,47 @@ void mark_join_nest_as_const(JOIN *join,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@brief Get the condition that can be used to do range analysis/partition
|
||||
pruning/etc
|
||||
|
||||
@detail
|
||||
Figure out which condition we can use:
|
||||
- For INNER JOIN, we use the WHERE,
|
||||
- "t1 LEFT JOIN t2 ON ..." uses t2's ON expression
|
||||
- "t1 LEFT JOIN (...) ON ..." uses the join nest's ON expression.
|
||||
*/
|
||||
|
||||
static Item **get_sargable_cond(JOIN *join, TABLE *table)
|
||||
{
|
||||
Item **retval;
|
||||
if (table->pos_in_table_list->on_expr)
|
||||
{
|
||||
/*
|
||||
This is an inner table from a single-table LEFT JOIN, "t1 LEFT JOIN
|
||||
t2 ON cond". Use the condition cond.
|
||||
*/
|
||||
retval= &table->pos_in_table_list->on_expr;
|
||||
}
|
||||
else if (table->pos_in_table_list->embedding &&
|
||||
!table->pos_in_table_list->embedding->sj_on_expr)
|
||||
{
|
||||
/*
|
||||
This is the inner side of a multi-table outer join. Use the
|
||||
appropriate ON expression.
|
||||
*/
|
||||
retval= &(table->pos_in_table_list->embedding->on_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The table is not inner wrt some LEFT JOIN. Use the WHERE clause */
|
||||
retval= &join->conds;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Calculate the best possible join and initialize the join structure.
|
||||
|
||||
|
@ -4919,42 +4953,11 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
|||
SQL_SELECT *select= 0;
|
||||
if (!s->const_keys.is_clear_all())
|
||||
{
|
||||
Item *sargable_cond;
|
||||
int cond_source;
|
||||
/*
|
||||
Figure out which condition we should use for range analysis. For
|
||||
INNER JOIN, we use the WHERE, for inner side of LEFT JOIN we should
|
||||
use the ON expression.
|
||||
*/
|
||||
if (*s->on_expr_ref)
|
||||
{
|
||||
/*
|
||||
This is an inner table from a single-table LEFT JOIN, "t1 LEFT JOIN
|
||||
t2 ON cond". Use the condition cond.
|
||||
*/
|
||||
cond_source= 0;
|
||||
sargable_cond= *s->on_expr_ref;
|
||||
}
|
||||
else if (s->table->pos_in_table_list->embedding &&
|
||||
!s->table->pos_in_table_list->embedding->sj_on_expr)
|
||||
{
|
||||
/*
|
||||
This is the inner side of a multi-table outer join. Use the
|
||||
appropriate ON expression.
|
||||
*/
|
||||
cond_source= 1;
|
||||
sargable_cond= s->table->pos_in_table_list->embedding->on_expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The table is not inner wrt some LEFT JOIN. Use the WHERE clause */
|
||||
cond_source= 2;
|
||||
sargable_cond= join->conds;
|
||||
}
|
||||
Item **sargable_cond= get_sargable_cond(join, s->table);
|
||||
|
||||
select= make_select(s->table, found_const_table_map,
|
||||
found_const_table_map,
|
||||
sargable_cond,
|
||||
*sargable_cond,
|
||||
(SORT_INFO*) 0,
|
||||
1, &error);
|
||||
if (!select)
|
||||
|
@ -4966,19 +4969,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
|||
Range analyzer might have modified the condition. Put it the new
|
||||
condition to where we got it from.
|
||||
*/
|
||||
switch (cond_source) {
|
||||
case 0:
|
||||
*s->on_expr_ref= select->cond;
|
||||
break;
|
||||
case 1:
|
||||
s->table->pos_in_table_list->embedding->on_expr= select->cond;
|
||||
break;
|
||||
case 2:
|
||||
join->conds= select->cond;
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
*sargable_cond= select->cond;
|
||||
|
||||
s->quick=select->quick;
|
||||
s->needed_reg=select->needed_reg;
|
||||
|
|
|
@ -263,8 +263,12 @@ typedef struct st_join_table {
|
|||
/*
|
||||
Pointer to the associated ON expression. on_expr_ref=!NULL except for
|
||||
degenerate joins.
|
||||
*on_expr_ref!=NULL for tables that are first inner tables within an outer
|
||||
join.
|
||||
|
||||
Optimization phase: *on_expr_ref!=NULL for tables that are the single
|
||||
tables on the inner side of the outer join (t1 LEFT JOIN t2 ON...)
|
||||
|
||||
Execution phase: *on_expr_ref!=NULL for tables that are first inner tables
|
||||
within an outer join (which may have multiple tables)
|
||||
*/
|
||||
Item **on_expr_ref;
|
||||
COND_EQUAL *cond_equal; /**< multiple equalities for the on expression */
|
||||
|
|
Loading…
Reference in a new issue