Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite3967a1

Browse files
committed
Improve pruning of a default partition
When querying a partitioned table containing a default partition, wewere wrongly deciding to include it in the scan too early in theprocess, failing to exclude it in some cases. If we reinterpret thePruneStepResult.scan_default flag slightly, we can do a better job atdetecting that it can be excluded. The change is that we avoid settingthe flag for that pruning step unless the step absolutely requires thedefault partition to be scanned (in contrast with the previousarrangement, which was to set it unless the step was able to prune it).So get_matching_partitions() must explicitly check the partition thateach returned bound value corresponds to in order to determine whetherthe default one needs to be included, rather than relying on the flagfrom the final step result.Author: Yuzuko Hosoya <hosoya.yuzuko@lab.ntt.co.jp>Reviewed-by: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>Discussion:https://postgr.es/m/00e601d4ca86$932b8bc0$b982a340$@lab.ntt.co.jp
1 parent082c9f5 commite3967a1

File tree

4 files changed

+111
-130
lines changed

4 files changed

+111
-130
lines changed

‎src/backend/partitioning/partprune.c

Lines changed: 98 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
714714
PruneStepResult**results,
715715
*final_result;
716716
ListCell*lc;
717+
boolscan_default;
717718

718719
/* If there are no pruning steps then all partitions match. */
719720
if (num_steps==0)
@@ -765,30 +766,39 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
765766
Assert(final_result!=NULL);
766767
i=-1;
767768
result=NULL;
769+
scan_default=final_result->scan_default;
768770
while ((i=bms_next_member(final_result->bound_offsets,i)) >=0)
769771
{
770772
intpartindex=context->boundinfo->indexes[i];
771773

772-
/*
773-
* In range and hash partitioning cases, some slots may contain -1,
774-
* indicating that no partition has been defined to accept a given
775-
* range of data or for a given remainder, respectively. The default
776-
* partition, if any, in case of range partitioning, will be added to
777-
* the result, because the specified range still satisfies the query's
778-
* conditions.
779-
*/
780-
if (partindex >=0)
781-
result=bms_add_member(result,partindex);
774+
if (partindex<0)
775+
{
776+
/*
777+
* In range partitioning cases, if a partition index is -1 it
778+
* means that the bound at the offset is the upper bound for a
779+
* range not covered by any partition (other than a possible
780+
* default partition). In hash partitioning, the same means no
781+
* partition has been defined for the corresponding remainder
782+
* value.
783+
*
784+
* In either case, the value is still part of the queried range of
785+
* values, so mark to scan the default partition if one exists.
786+
*/
787+
scan_default |=partition_bound_has_default(context->boundinfo);
788+
continue;
789+
}
790+
791+
result=bms_add_member(result,partindex);
782792
}
783793

784-
/* Add the null and/or default partition if needed andifpresent. */
794+
/* Add the null and/or default partition if needed and present. */
785795
if (final_result->scan_null)
786796
{
787797
Assert(context->strategy==PARTITION_STRATEGY_LIST);
788798
Assert(partition_bound_accepts_nulls(context->boundinfo));
789799
result=bms_add_member(result,context->boundinfo->null_index);
790800
}
791-
if (final_result->scan_default)
801+
if (scan_default)
792802
{
793803
Assert(context->strategy==PARTITION_STRATEGY_LIST||
794804
context->strategy==PARTITION_STRATEGY_RANGE);
@@ -2412,6 +2422,11 @@ get_matching_hash_bounds(PartitionPruneContext *context,
24122422
* get_matching_list_bounds
24132423
*Determine the offsets of list bounds matching the specified value,
24142424
*according to the semantics of the given operator strategy
2425+
*
2426+
* scan_default will be set in the returned struct, if the default partition
2427+
* needs to be scanned, provided one exists at all. scan_null will be set if
2428+
* the special null-accepting partition needs to be scanned.
2429+
*
24152430
* 'opstrategy' if non-zero must be a btree strategy number.
24162431
*
24172432
* 'value' contains the value to use for pruning.
@@ -2614,8 +2629,13 @@ get_matching_list_bounds(PartitionPruneContext *context,
26142629
* Each datum whose offset is in result is to be treated as the upper bound of
26152630
* the partition that will contain the desired values.
26162631
*
2617-
* If default partition needs to be scanned for given values, set scan_default
2618-
* in result if present.
2632+
* scan_default is set in the returned struct if a default partition exists
2633+
* and we're absolutely certain that it needs to be scanned. We do *not* set
2634+
* it just because values match portions of the key space uncovered by
2635+
* partitions other than default (space which we normally assume to belong to
2636+
* the default partition): the final set of bounds obtained after combining
2637+
* multiple pruning steps might exclude it, so we infer its inclusion
2638+
* elsewhere.
26192639
*
26202640
* 'opstrategy' if non-zero must be a btree strategy number.
26212641
*
@@ -2641,8 +2661,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
26412661
int*partindices=boundinfo->indexes;
26422662
intoff,
26432663
minoff,
2644-
maxoff,
2645-
i;
2664+
maxoff;
26462665
boolis_equal;
26472666
boolinclusive= false;
26482667

@@ -2672,13 +2691,15 @@ get_matching_range_bounds(PartitionPruneContext *context,
26722691
*/
26732692
if (nvalues==0)
26742693
{
2694+
/* ignore key space not covered by any partitions */
26752695
if (partindices[minoff]<0)
26762696
minoff++;
26772697
if (partindices[maxoff]<0)
26782698
maxoff--;
26792699

26802700
result->scan_default=partition_bound_has_default(boundinfo);
2681-
Assert(minoff >=0&&maxoff >=0);
2701+
Assert(partindices[minoff] >=0&&
2702+
partindices[maxoff] >=0);
26822703
result->bound_offsets=bms_add_range(NULL,minoff,maxoff);
26832704

26842705
returnresult;
@@ -2706,11 +2727,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
27062727
if (nvalues==partnatts)
27072728
{
27082729
/* There can only be zero or one matching partition. */
2709-
if (partindices[off+1] >=0)
2710-
result->bound_offsets=bms_make_singleton(off+1);
2711-
else
2712-
result->scan_default=
2713-
partition_bound_has_default(boundinfo);
2730+
result->bound_offsets=bms_make_singleton(off+1);
27142731
returnresult;
27152732
}
27162733
else
@@ -2798,57 +2815,21 @@ get_matching_range_bounds(PartitionPruneContext *context,
27982815
maxoff=off+1;
27992816
}
28002817

2801-
/*
2802-
* Skip if minoff/maxoff are actually the upper bound of a
2803-
* un-assigned portion of values.
2804-
*/
2805-
if (partindices[minoff]<0&&minoff<boundinfo->ndatums)
2806-
minoff++;
2807-
if (partindices[maxoff]<0&&maxoff >=1)
2808-
maxoff--;
2809-
2810-
/*
2811-
* There may exist a range of values unassigned to any
2812-
* non-default partition between the datums at minoff and
2813-
* maxoff. Add the default partition in that case.
2814-
*/
2815-
if (partition_bound_has_default(boundinfo))
2816-
{
2817-
for (i=minoff;i <=maxoff;i++)
2818-
{
2819-
if (partindices[i]<0)
2820-
{
2821-
result->scan_default= true;
2822-
break;
2823-
}
2824-
}
2825-
}
2826-
28272818
Assert(minoff >=0&&maxoff >=0);
28282819
result->bound_offsets=bms_add_range(NULL,minoff,maxoff);
28292820
}
2830-
elseif (off >=0)/* !is_equal */
2821+
else
28312822
{
28322823
/*
28332824
* The lookup value falls in the range between some bounds in
28342825
* boundinfo. 'off' would be the offset of the greatest bound
28352826
* that is <= lookup value, so add off + 1 to the result
28362827
* instead as the offset of the upper bound of the only
2837-
* partition that may contain the lookup value.
2838-
*/
2839-
if (partindices[off+1] >=0)
2840-
result->bound_offsets=bms_make_singleton(off+1);
2841-
else
2842-
result->scan_default=
2843-
partition_bound_has_default(boundinfo);
2844-
}
2845-
else
2846-
{
2847-
/*
2848-
* off < 0: the lookup value is smaller than all bounds, so
2849-
* only the default partition qualifies, if there is one.
2828+
* partition that may contain the lookup value. If 'off' is
2829+
* -1 indicating that all bounds are greater, then we simply
2830+
* end up adding the first bound's offset, that is, 0.
28502831
*/
2851-
result->scan_default=partition_bound_has_default(boundinfo);
2832+
result->bound_offsets=bms_make_singleton(off+1);
28522833
}
28532834

28542835
returnresult;
@@ -2919,16 +2900,18 @@ get_matching_range_bounds(PartitionPruneContext *context,
29192900

29202901
minoff=inclusive ?off :off+1;
29212902
}
2922-
2923-
/*
2924-
* lookup value falls in the range between some bounds in
2925-
* boundinfo. off would be the offset of the greatest bound
2926-
* that is <= lookup value, so add off + 1 to the result
2927-
* instead as the offset of the upper bound of the smallest
2928-
* partition that may contain the lookup value.
2929-
*/
29302903
else
2904+
{
2905+
2906+
/*
2907+
* lookup value falls in the range between some bounds in
2908+
* boundinfo. off would be the offset of the greatest
2909+
* bound that is <= lookup value, so add off + 1 to the
2910+
* result instead as the offset of the upper bound of the
2911+
* smallest partition that may contain the lookup value.
2912+
*/
29312913
minoff=off+1;
2914+
}
29322915
}
29332916
break;
29342917

@@ -2946,16 +2929,7 @@ get_matching_range_bounds(PartitionPruneContext *context,
29462929
boundinfo,
29472930
nvalues,values,
29482931
&is_equal);
2949-
if (off<0)
2950-
{
2951-
/*
2952-
* All bounds are greater than the key, so we could only
2953-
* expect to find the lookup key in the default partition.
2954-
*/
2955-
result->scan_default=partition_bound_has_default(boundinfo);
2956-
returnresult;
2957-
}
2958-
else
2932+
if (off >=0)
29592933
{
29602934
/*
29612935
* See the comment above.
@@ -3003,65 +2977,58 @@ get_matching_range_bounds(PartitionPruneContext *context,
30032977
else
30042978
maxoff=off;
30052979
}
2980+
else
2981+
{
2982+
/*
2983+
* 'off' is -1 indicating that all bounds are greater, so just
2984+
* set the first bound's offset as maxoff.
2985+
*/
2986+
maxoff=off+1;
2987+
}
30062988
break;
30072989

30082990
default:
30092991
elog(ERROR,"invalid strategy number %d",opstrategy);
30102992
break;
30112993
}
30122994

2995+
Assert(minoff >=0&&minoff <=boundinfo->ndatums);
2996+
Assert(maxoff >=0&&maxoff <=boundinfo->ndatums);
2997+
30132998
/*
3014-
* Skip a gap and when doing so, check if the bound contains a finite
3015-
* value to decide if we need to add the default partition. If it's an
3016-
* infinite bound, we need not add the default partition, as having an
3017-
* infinite bound means the partition in question catches any values that
3018-
* would otherwise be in the default partition.
2999+
* If the smallest partition to return has MINVALUE (negative infinity) as
3000+
* its lower bound, increment it to point to the next finite bound
3001+
* (supposedly its upper bound), so that we don't advertently end up
3002+
* scanning the default partition.
30193003
*/
3020-
if (partindices[minoff]<0)
3004+
if (minoff<boundinfo->ndatums&&partindices[minoff]<0)
30213005
{
30223006
intlastkey=nvalues-1;
30233007

3024-
if (minoff >=0&&
3025-
minoff<boundinfo->ndatums&&
3026-
boundinfo->kind[minoff][lastkey]==
3027-
PARTITION_RANGE_DATUM_VALUE)
3028-
result->scan_default=partition_bound_has_default(boundinfo);
3029-
3030-
minoff++;
3008+
if (boundinfo->kind[minoff][lastkey]==
3009+
PARTITION_RANGE_DATUM_MINVALUE)
3010+
{
3011+
minoff++;
3012+
Assert(boundinfo->indexes[minoff] >=0);
3013+
}
30313014
}
30323015

30333016
/*
3034-
* Skip a gap. See the above comment about how we decide whether or not
3035-
* to scan the default partition based whether the datum that will become
3036-
* the maximum datum is finite or not.
3017+
* If the previous greatest partition has MAXVALUE (positive infinity) as
3018+
* its upper bound (something only possible to do with multi-column range
3019+
* partitioning), we scan switch to it as the greatest partition to
3020+
* return. Again, so that we don't advertently end up scanning the
3021+
* default partition.
30373022
*/
30383023
if (maxoff >=1&&partindices[maxoff]<0)
30393024
{
30403025
intlastkey=nvalues-1;
30413026

3042-
if (maxoff >=0&&
3043-
maxoff <=boundinfo->ndatums&&
3044-
boundinfo->kind[maxoff-1][lastkey]==
3045-
PARTITION_RANGE_DATUM_VALUE)
3046-
result->scan_default=partition_bound_has_default(boundinfo);
3047-
3048-
maxoff--;
3049-
}
3050-
3051-
if (partition_bound_has_default(boundinfo))
3052-
{
3053-
/*
3054-
* There may exist a range of values unassigned to any non-default
3055-
* partition between the datums at minoff and maxoff. Add the default
3056-
* partition in that case.
3057-
*/
3058-
for (i=minoff;i <=maxoff;i++)
3027+
if (boundinfo->kind[maxoff-1][lastkey]==
3028+
PARTITION_RANGE_DATUM_MAXVALUE)
30593029
{
3060-
if (partindices[i]<0)
3061-
{
3062-
result->scan_default= true;
3063-
break;
3064-
}
3030+
maxoff--;
3031+
Assert(boundinfo->indexes[maxoff] >=0);
30653032
}
30663033
}
30673034

@@ -3306,14 +3273,24 @@ perform_pruning_combine_step(PartitionPruneContext *context,
33063273

33073274
/*
33083275
* A combine step without any source steps is an indication to not perform
3309-
* any partition pruning, we just returnallpartitions.
3276+
* any partition pruning. Returnalldatum indexes in that case.
33103277
*/
33113278
result= (PruneStepResult*)palloc0(sizeof(PruneStepResult));
33123279
if (list_length(cstep->source_stepids)==0)
33133280
{
33143281
PartitionBoundInfoboundinfo=context->boundinfo;
3282+
intrangemax;
3283+
3284+
/*
3285+
* Add all valid offsets into the boundinfo->indexes array. For range
3286+
* partitioning, boundinfo->indexes contains (boundinfo->ndatums + 1)
3287+
* valid entries; otherwise there are boundinfo->ndatums.
3288+
*/
3289+
rangemax=context->strategy==PARTITION_STRATEGY_RANGE ?
3290+
boundinfo->ndatums :boundinfo->ndatums-1;
33153291

3316-
result->bound_offsets=bms_add_range(NULL,0,boundinfo->ndatums-1);
3292+
result->bound_offsets=
3293+
bms_add_range(result->bound_offsets,0,rangemax);
33173294
result->scan_default=partition_bound_has_default(boundinfo);
33183295
result->scan_null=partition_bound_accepts_nulls(boundinfo);
33193296
returnresult;

‎src/include/partitioning/partbounds.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
* pointed by remainder produced when hash value of the datum-tuple is divided
5757
* by the greatest modulus.
5858
*/
59-
6059
typedefstructPartitionBoundInfoData
6160
{
6261
charstrategy;/* hash, list or range? */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp