Commit 93669bfe authored by sergefp@mysql.com's avatar sergefp@mysql.com

WL#2985 "Partition Pruning":

- post-...-post review fixes
- Added "integer range walking" that allows to do partition pruning for "a <=? t.field <=? b"
  by finding used partitions for a, a+1, a+2, ..., b-1, b. 
parent f2d603c2
...@@ -274,3 +274,33 @@ id select_type table partitions type possible_keys key key_len ref rows Extra ...@@ -274,3 +274,33 @@ id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE X p1,p2 ALL a NULL NULL NULL 4 Using where 1 SIMPLE X p1,p2 ALL a NULL NULL NULL 4 Using where
1 SIMPLE Y p1,p2 ref a a 4 test.X.a 2 1 SIMPLE Y p1,p2 ref a a 4 test.X.a 2
drop table t1; drop table t1;
create table t1 (a int) partition by hash(a) partitions 20;
insert into t1 values (1),(2),(3);
explain partitions select * from t1 where a > 1 and a < 3;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p2 ALL NULL NULL NULL NULL 3 Using where
explain partitions select * from t1 where a >= 1 and a < 3;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 3 Using where
explain partitions select * from t1 where a > 1 and a <= 3;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p2,p3 ALL NULL NULL NULL NULL 3 Using where
explain partitions select * from t1 where a >= 1 and a <= 3;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p1,p2,p3 ALL NULL NULL NULL NULL 3 Using where
drop table t1;
create table t1 (a int, b int)
partition by list(a) subpartition by hash(b) subpartitions 20
(
partition p0 values in (0),
partition p1 values in (1),
partition p2 values in (2),
partition p3 values in (3)
);
insert into t1 values (1,1),(2,2),(3,3);
explain partitions select * from t1 where b > 1 and b < 3;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p0_sp2,p1_sp2,p2_sp2,p3_sp2 ALL NULL NULL NULL NULL 3 Using where
explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2);
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p1_sp2,p2_sp2 ALL NULL NULL NULL NULL 3 Using where
...@@ -209,7 +209,7 @@ create table t1 (a int not null, b int not null) partition by LIST (a+b) ( ...@@ -209,7 +209,7 @@ create table t1 (a int not null, b int not null) partition by LIST (a+b) (
partition p0 values in (12), partition p0 values in (12),
partition p1 values in (14) partition p1 values in (14)
); );
--error 1500 --error ER_NO_PARTITION_FOR_GIVEN_VALUE
insert into t1 values (10,1); insert into t1 values (10,1);
drop table t1; drop table t1;
......
...@@ -247,5 +247,28 @@ explain partitions ...@@ -247,5 +247,28 @@ explain partitions
select * from t1 X, t1 Y where X.a = Y.a and (X.a=1 or X.a=2); select * from t1 X, t1 Y where X.a = Y.a and (X.a=1 or X.a=2);
drop table t1; drop table t1;
# Tests for "short ranges"
create table t1 (a int) partition by hash(a) partitions 20;
insert into t1 values (1),(2),(3);
explain partitions select * from t1 where a > 1 and a < 3;
explain partitions select * from t1 where a >= 1 and a < 3;
explain partitions select * from t1 where a > 1 and a <= 3;
explain partitions select * from t1 where a >= 1 and a <= 3;
drop table t1;
create table t1 (a int, b int)
partition by list(a) subpartition by hash(b) subpartitions 20
(
partition p0 values in (0),
partition p1 values in (1),
partition p2 values in (2),
partition p3 values in (3)
);
insert into t1 values (1,1),(2,2),(3,3);
explain partitions select * from t1 where b > 1 and b < 3;
explain partitions select * from t1 where b > 1 and b < 3 and (a =1 or a =2);
# No tests for NULLs in RANGE(monotonic_expr()) - they depend on BUG#15447 # No tests for NULLs in RANGE(monotonic_expr()) - they depend on BUG#15447
# being fixed. # being fixed.
...@@ -474,6 +474,8 @@ typedef struct { ...@@ -474,6 +474,8 @@ typedef struct {
uint32 end_part; uint32 end_part;
bool use_bit_array; bool use_bit_array;
} part_id_range; } part_id_range;
/** /**
* An enum and a struct to handle partitioning and subpartitioning. * An enum and a struct to handle partitioning and subpartitioning.
*/ */
...@@ -537,7 +539,109 @@ typedef bool (*get_part_id_func)(partition_info *part_info, ...@@ -537,7 +539,109 @@ typedef bool (*get_part_id_func)(partition_info *part_info,
uint32 *part_id); uint32 *part_id);
typedef uint32 (*get_subpart_id_func)(partition_info *part_info); typedef uint32 (*get_subpart_id_func)(partition_info *part_info);
class partition_info :public Sql_alloc {
struct st_partition_iter;
#define NOT_A_PARTITION_ID ((uint32)-1)
/*
A "Get next" function for partition iterator.
SYNOPSIS
partition_iter_func()
part_iter Partition iterator, you call only "iter.get_next(&iter)"
RETURN
NOT_A_PARTITION_ID if there are no more partitions.
[sub]partition_id of the next partition
*/
typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter);
/*
Partition set iterator. Used to enumerate a set of [sub]partitions
obtained in partition interval analysis (see get_partitions_in_range_iter).
For the user, the only meaningful field is get_next, which may be used as
follows:
part_iterator.get_next(&part_iterator);
Initialization is done by any of the following calls:
- get_partitions_in_range_iter-type function call
- init_single_partition_iterator()
- init_all_partitions_iterator()
Cleanup is not needed.
*/
typedef struct st_partition_iter
{
partition_iter_func get_next;
union {
struct {
uint32 start_part_num;
uint32 end_part_num;
};
struct {
longlong start_val;
longlong end_val;
};
bool null_returned;
};
partition_info *part_info;
} PARTITION_ITERATOR;
/*
Get an iterator for set of partitions that match given field-space interval
SYNOPSIS
get_partitions_in_range_iter()
part_info Partitioning info
is_subpart
min_val Left edge, field value in opt_range_key format.
max_val Right edge, field value in opt_range_key format.
flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
NO_MAX_RANGE.
part_iter Iterator structure to be initialized
DESCRIPTION
Functions with this signature are used to perform "Partitioning Interval
Analysis". This analysis is applicable for any type of [sub]partitioning
by some function of a single fieldX. The idea is as follows:
Given an interval "const1 <=? fieldX <=? const2", find a set of partitions
that may contain records with value of fieldX within the given interval.
The min_val, max_val and flags parameters specify the interval.
The set of partitions is returned by initializing an iterator in *part_iter
NOTES
There are currently two functions of this type:
- get_part_iter_for_interval_via_walking
- get_part_iter_for_interval_via_mapping
RETURN
0 - No matching partitions, iterator not initialized
1 - Some partitions would match, iterator intialized for traversing them
-1 - All partitions would match, iterator not initialized
*/
typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
bool is_subpart,
byte *min_val, byte *max_val,
uint flags,
PARTITION_ITERATOR *part_iter);
/* Initialize the iterator to return a single partition with given part_id */
inline void init_single_partition_iterator(uint32 part_id,
PARTITION_ITERATOR *part_iter);
/* Initialize the iterator to enumerate all partitions */
inline void init_all_partitions_iterator(partition_info *part_info,
PARTITION_ITERATOR *part_iter);
class partition_info : public Sql_alloc
{
public: public:
/* /*
* Here comes a set of definitions needed for partitioned table handlers. * Here comes a set of definitions needed for partitioned table handlers.
...@@ -566,7 +670,7 @@ class partition_info :public Sql_alloc { ...@@ -566,7 +670,7 @@ class partition_info :public Sql_alloc {
same in all subpartitions same in all subpartitions
*/ */
get_subpart_id_func get_subpartition_id; get_subpart_id_func get_subpartition_id;
/* NULL-terminated array of fields used in partitioned expression */ /* NULL-terminated array of fields used in partitioned expression */
Field **part_field_array; Field **part_field_array;
/* NULL-terminated array of fields used in subpartitioned expression */ /* NULL-terminated array of fields used in subpartitioned expression */
...@@ -598,6 +702,39 @@ class partition_info :public Sql_alloc { ...@@ -598,6 +702,39 @@ class partition_info :public Sql_alloc {
longlong *range_int_array; longlong *range_int_array;
LIST_PART_ENTRY *list_array; LIST_PART_ENTRY *list_array;
}; };
/********************************************
* INTERVAL ANALYSIS
********************************************/
/*
Partitioning interval analysis function for partitioning, or NULL if
interval analysis is not supported for this kind of partitioning.
*/
get_partitions_in_range_iter get_part_iter_for_interval;
/*
Partitioning interval analysis function for subpartitioning, or NULL if
interval analysis is not supported for this kind of partitioning.
*/
get_partitions_in_range_iter get_subpart_iter_for_interval;
/*
Valid iff
get_part_iter_for_interval=get_part_iter_for_interval_via_walking:
controls how we'll process "field < C" and "field > C" intervals.
If the partitioning function F is strictly increasing, then for any x, y
"x < y" => "F(x) < F(y)" (*), i.e. when we get interval "field < C"
we can perform partition pruning on the equivalent "F(field) < F(C)".
If the partitioning function not strictly increasing (it is simply
increasing), then instead of (*) we get "x < y" => "F(x) <= F(y)"
i.e. for interval "field < C" we can perform partition pruning for
"F(field) <= F(C)".
*/
bool range_analysis_include_bounds;
/********************************************
* INTERVAL ANALYSIS ENDS
********************************************/
char* part_info_string; char* part_info_string;
char *part_func_string; char *part_func_string;
...@@ -681,6 +818,25 @@ class partition_info :public Sql_alloc { ...@@ -681,6 +818,25 @@ class partition_info :public Sql_alloc {
#ifdef WITH_PARTITION_STORAGE_ENGINE #ifdef WITH_PARTITION_STORAGE_ENGINE
uint32 get_next_partition_id_range(struct st_partition_iter* part_iter);
inline void init_single_partition_iterator(uint32 part_id,
PARTITION_ITERATOR *part_iter)
{
part_iter->start_part_num= part_id;
part_iter->end_part_num= part_id+1;
part_iter->get_next= get_next_partition_id_range;
}
inline
void init_all_partitions_iterator(partition_info *part_info,
PARTITION_ITERATOR *part_iter)
{
part_iter->start_part_num= 0;
part_iter->end_part_num= part_info->no_parts;
part_iter->get_next= get_next_partition_id_range;
}
/* /*
Answers the question if subpartitioning is used for a certain table Answers the question if subpartitioning is used for a certain table
SYNOPSIS SYNOPSIS
......
This diff is collapsed.
This diff is collapsed.
...@@ -638,6 +638,11 @@ JOIN::optimize() ...@@ -638,6 +638,11 @@ JOIN::optimize()
TABLE_LIST *tbl; TABLE_LIST *tbl;
for (tbl= select_lex->leaf_tables; tbl; tbl= tbl->next_leaf) for (tbl= select_lex->leaf_tables; tbl; tbl= tbl->next_leaf)
{ {
/*
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) if (!tbl->embedding)
{ {
Item *prune_cond= tbl->on_expr? tbl->on_expr : conds; Item *prune_cond= tbl->on_expr? tbl->on_expr : conds;
......
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