Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
0f1fa93a
Commit
0f1fa93a
authored
Jan 05, 2006
by
unknown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WL#2985 "Partition-pruning", "range walking" addition: better comments.
parent
bcd56c6d
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
102 additions
and
34 deletions
+102
-34
sql/handler.h
sql/handler.h
+2
-3
sql/opt_range.cc
sql/opt_range.cc
+86
-21
sql/sql_partition.cc
sql/sql_partition.cc
+14
-10
No files found.
sql/handler.h
View file @
0f1fa93a
...
@@ -690,11 +690,10 @@ public:
...
@@ -690,11 +690,10 @@ public:
/*
/*
A bitmap of partitions used by the current query.
A bitmap of partitions used by the current query.
Usage pattern:
Usage pattern:
* It is guaranteed that all partitions are set to be unused on query start.
* The handler->extra(HA_EXTRA_RESET) call at query start/end sets all
partitions to be unused.
* Before index/rnd_init(), partition pruning code sets the bits for used
* Before index/rnd_init(), partition pruning code sets the bits for used
partitions.
partitions.
* The handler->extra(HA_EXTRA_RESET) call at query end sets all partitions
to be unused.
*/
*/
MY_BITMAP
used_partitions
;
MY_BITMAP
used_partitions
;
...
...
sql/opt_range.cc
View file @
0f1fa93a
...
@@ -2115,7 +2115,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
...
@@ -2115,7 +2115,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
The list of intervals we'll obtain will look like this:
The list of intervals we'll obtain will look like this:
((t1.a, t1.b) = (1,'foo')),
((t1.a, t1.b) = (1,'foo')),
((t1.a, t1.b) = (2,'bar')),
((t1.a, t1.b) = (2,'bar')),
((t1,a, t1.b) > (10,'zz'))
(**)
((t1,a, t1.b) > (10,'zz'))
2. for each interval I
2. for each interval I
{
{
...
@@ -2574,30 +2574,95 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge)
...
@@ -2574,30 +2574,95 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge)
This function
This function
* recursively walks the SEL_ARG* tree collecting partitioning "intervals"
* recursively walks the SEL_ARG* tree collecting partitioning "intervals"
* finds the partitions one needs to use to get rows in these intervals
* finds the partitions one needs to use to get rows in these intervals
* marks these partitions as used
* marks these partitions as used.
The next session desribes the process in greater detail.
NOTES
IMPLEMENTATION
WHAT IS CONSIDERED TO BE "INTERVALS"
TYPES OF RESTRICTIONS THAT WE CAN OBTAIN PARTITIONS FOR
A partition pruning "interval" is equivalent to condition in one of the
We can find out which [sub]partitions to use if we obtain restrictions on
forms:
[sub]partitioning fields in the following form:
1. "partition_field1=const1 AND ... AND partition_fieldN=constN"
"partition_field1=const1 AND ... AND partition_fieldN=constN" (1)
1.1 Same as (1) but for subpartition fields
"subpartition_field1=const1 AND ... AND subpartition_fieldN=constN" (2)
"(1) AND (2)" (3)
If partitioning supports interval analysis (i.e. partitioning is a
function of a single table field, and partition_info::
In (1) and (2) all [sub]partitioning fields must be used, and "x=const"
get_part_iter_for_interval != NULL), then we can also use condition in
includes "x IS NULL".
this form:
2. "const1 <=? partition_field <=? const2"
If partitioning is performed using
2.1 Same as (2) but for subpartition_field
PARTITION BY RANGE(unary_monotonic_func(single_partition_field)),
INFERRING THE RESTRICTIONS FROM SEL_ARG TREE
then the following is also an interval:
The below is an example of what SEL_ARG tree may represent:
" const1 OP1 single_partition_field OP2 const2" (4)
(start)
| $
| Partitioning keyparts $ subpartitioning keyparts
| $
| ... ... $
| | | $
| +---------+ +---------+ $ +-----------+ +-----------+
\-| par1=c1 |--| par2=c2 |-----| subpar1=c3|--| subpar2=c5|
+---------+ +---------+ $ +-----------+ +-----------+
| $ | |
| $ | +-----------+
| $ | | subpar2=c6|
| $ | +-----------+
| $ |
| $ +-----------+ +-----------+
| $ | subpar1=c4|--| subpar2=c8|
| $ +-----------+ +-----------+
| $
| $
+---------+ $ +------------+ +------------+
| par1=c2 |------------------| subpar1=c10|--| subpar2=c12|
+---------+ $ +------------+ +------------+
| $
... $
The up-down connections are connections via SEL_ARG::left and
SEL_ARG::right. A horizontal connection to the right is the
SEL_ARG::next_key_part connection.
find_used_partitions() traverses the entire tree via recursion on
* SEL_ARG::next_key_part (from left to right on the picture)
* SEL_ARG::left|right (up/down on the pic). Left-right recursion is
performed for each depth level.
Recursion descent on SEL_ARG::next_key_part is used to accumulate (in
ppar->arg_stack) constraints on partitioning and subpartitioning fields.
For the example in the above picture, one of stack states is:
in find_used_partitions(key_tree = "subpar2=c5") (***)
in find_used_partitions(key_tree = "subpar1=c3")
in find_used_partitions(key_tree = "par2=c2") (**)
in find_used_partitions(key_tree = "par1=c1")
in prune_partitions(...)
We apply partitioning limits as soon as possible, e.g. when we reach the
depth (**), we find which partition(s) correspond to "par1=c1 AND par2=c2",
and save them in ppar->part_iter.
When we reach the depth (***), we find which subpartition(s) correspond to
"subpar1=c3 AND subpar2=c5", and then mark appropriate subpartitions in
appropriate subpartitions as used.
It is possible that constraints on some partitioning fields are missing.
For the above example, consider this stack state:
in find_used_partitions(key_tree = "subpar2=c12") (***)
in find_used_partitions(key_tree = "subpar1=c10")
in find_used_partitions(key_tree = "par1=c2")
in prune_partitions(...)
Here we don't have constraints for all partitioning fields. Since we've
never set the ppar->part_iter to contain used set of partitions, we use
its default "all partitions" value. We get subpartition id for
"subpar1=c3 AND subpar2=c5", and mark that subpartition as used in every
partition.
The inverse is also possible: we may get constraints on partitioning
fields, but not constraints on subpartitioning fields. In that case,
calls to find_used_partitions() with depth below (**) will return -1,
and we will mark entire partition as used.
where OP1 and OP2 are '<' OR '<=', and const_i can be +/- inf.
TODO
Everything else is not a partition pruning "interval".
Replace recursion on SEL_ARG::left and SEL_ARG::right with a loop
RETURN
RETURN
1 OK, one or more [sub]partitions are marked as used.
1 OK, one or more [sub]partitions are marked as used.
...
...
sql/sql_partition.cc
View file @
0f1fa93a
...
@@ -3673,11 +3673,11 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
...
@@ -3673,11 +3673,11 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
DESCRIPTION
DESCRIPTION
Initialize partition set iterator to walk over the interval in
Initialize partition set iterator to walk over the interval in
ordered-
list
-of-partitions (for RANGE partitioning) or
ordered-
array
-of-partitions (for RANGE partitioning) or
ordered-
list
-of-list-constants (for LIST partitioning) space.
ordered-
array
-of-list-constants (for LIST partitioning) space.
IMPLEMENTATION
IMPLEMENTATION
This function is
appli
ed when partitioning is done by
This function is
us
ed when partitioning is done by
<RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
<RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
t.field space into a sub-array of partition_info::range_int_array or
t.field space into a sub-array of partition_info::range_int_array or
partition_info::list_array (see get_partition_id_range_for_endpoint,
partition_info::list_array (see get_partition_id_range_for_endpoint,
...
@@ -3760,7 +3760,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
...
@@ -3760,7 +3760,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
/*
/*
Partitioning Interval Analysis: Initialize iterator to walk
integer
interval
Partitioning Interval Analysis: Initialize iterator to walk
field
interval
SYNOPSIS
SYNOPSIS
get_part_iter_for_interval_via_walking()
get_part_iter_for_interval_via_walking()
...
@@ -3776,7 +3776,8 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
...
@@ -3776,7 +3776,8 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
DESCRIPTION
DESCRIPTION
Initialize partition set iterator to walk over interval in integer field
Initialize partition set iterator to walk over interval in integer field
space. That is, for "const1 <=? t.field <=? const2" interval, initialize
space. That is, for "const1 <=? t.field <=? const2" interval, initialize
the iterator to do this:
the iterator to return a set of [sub]partitions obtained with the
following procedure:
get partition id for t.field = const1, return it
get partition id for t.field = const1, return it
get partition id for t.field = const1+1, return it
get partition id for t.field = const1+1, return it
... t.field = const1+2, ...
... t.field = const1+2, ...
...
@@ -3799,7 +3800,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
...
@@ -3799,7 +3800,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
The rationale behind these requirements is that if they are not met
The rationale behind these requirements is that if they are not met
we're likely to hit most of the partitions and traversing the interval
we're likely to hit most of the partitions and traversing the interval
will only add overhead. So it's better return "all partitions used" in
will only add overhead. So it's better return "all partitions used" in
th
is
case.
th
at
case.
RETURN
RETURN
0 - No matching partitions, iterator not initialized
0 - No matching partitions, iterator not initialized
...
@@ -3917,7 +3918,7 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
...
@@ -3917,7 +3918,7 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
part_iter Partition set iterator structure
part_iter Partition set iterator structure
DESCRIPTION
DESCRIPTION
This i
s special implementation of PARTITION_ITERATOR::get_next() for
This i
mplementation of PARTITION_ITERATOR::get_next() is special for
LIST partitioning: it enumerates partition ids in
LIST partitioning: it enumerates partition ids in
part_info->list_array[i] where i runs over [min_idx, max_idx] interval.
part_info->list_array[i] where i runs over [min_idx, max_idx] interval.
...
@@ -3937,13 +3938,16 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter)
...
@@ -3937,13 +3938,16 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter)
/*
/*
PARTITION_ITERATOR::get_next implementation: walk over
integer
interval
PARTITION_ITERATOR::get_next implementation: walk over
field-space
interval
SYNOPSIS
SYNOPSIS
get_next_partition_via_walking()
get_next_partition_via_walking()
part_iter Partitioning iterator
part_iter Partitioning iterator
DESCRIPTION
DESCRIPTION
This implementation of PARTITION_ITERATOR::get_next() returns ids of
partitions that contain records with partitioning field value within
[start_val, end_val] interval.
RETURN
RETURN
partition id
partition id
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment