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

Commit53d8695

Browse files
committed
Reduce the number of pallocs when building partition bounds
In each of the create_*_bound() functions for LIST, RANGE and HASHpartitioning, there were a large number of palloc calls which could bereduced down to a much smaller number.In each of these functions, an array was built so that we could qsort itbefore making the PartitionBoundInfo. For LIST and HASH partitioning, anarray of pointers was allocated then each element was allocated withinthat array. Since the number of items of each dimension is knownbeforehand, we can just allocate a single chunk of memory for this.Similarly, with all partition strategies, we're able to reduce the numberof allocations to build the ->datums field. This is an array of Datumpointers, but there's no need for the Datums that each element points toto be singly allocated. One big chunk will do. For RANGE partitioning,the PartitionBoundInfo->kind field can get the same treatment.We can apply the same optimizations to partition_bounds_copy(). Doingthis might have a small effect on cache performance when searching for thecorrect partition during partition pruning or DML on a partitioned table.However, that's likely to be small and this is mostly about reducingpalloc overhead.Author: Nitin Jadhav, Justin Pryzby, David RowleyReviewed-by: Justin Pryzby, Zhihong YuDiscussion:https://postgr.es/m/flat/CAMm1aWYFTqEio3bURzZh47jveiHRwgQTiSDvBORczNEz2duZ1Q@mail.gmail.com
1 parent2aca19f commit53d8695

File tree

1 file changed

+123
-71
lines changed

1 file changed

+123
-71
lines changed

‎src/backend/partitioning/partbounds.c

Lines changed: 123 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,10 @@ create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
358358
PartitionKeykey,int**mapping)
359359
{
360360
PartitionBoundInfoboundinfo;
361-
PartitionHashBound**hbounds=NULL;
361+
PartitionHashBound*hbounds;
362362
inti;
363-
intndatums=0;
364363
intgreatest_modulus;
364+
Datum*boundDatums;
365365

366366
boundinfo= (PartitionBoundInfoData*)
367367
palloc0(sizeof(PartitionBoundInfoData));
@@ -370,9 +370,8 @@ create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
370370
boundinfo->null_index=-1;
371371
boundinfo->default_index=-1;
372372

373-
ndatums=nparts;
374-
hbounds= (PartitionHashBound**)
375-
palloc(nparts*sizeof(PartitionHashBound*));
373+
hbounds= (PartitionHashBound*)
374+
palloc(nparts*sizeof(PartitionHashBound));
376375

377376
/* Convert from node to the internal representation */
378377
for (i=0;i<nparts;i++)
@@ -382,37 +381,44 @@ create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
382381
if (spec->strategy!=PARTITION_STRATEGY_HASH)
383382
elog(ERROR,"invalid strategy in partition bound spec");
384383

385-
hbounds[i]= (PartitionHashBound*)palloc(sizeof(PartitionHashBound));
386-
hbounds[i]->modulus=spec->modulus;
387-
hbounds[i]->remainder=spec->remainder;
388-
hbounds[i]->index=i;
384+
hbounds[i].modulus=spec->modulus;
385+
hbounds[i].remainder=spec->remainder;
386+
hbounds[i].index=i;
389387
}
390388

391389
/* Sort all the bounds in ascending order */
392-
qsort(hbounds,nparts,sizeof(PartitionHashBound*),
390+
qsort(hbounds,nparts,sizeof(PartitionHashBound),
393391
qsort_partition_hbound_cmp);
394392

395393
/* After sorting, moduli are now stored in ascending order. */
396-
greatest_modulus=hbounds[ndatums-1]->modulus;
394+
greatest_modulus=hbounds[nparts-1].modulus;
397395

398-
boundinfo->ndatums=ndatums;
399-
boundinfo->datums= (Datum**)palloc0(ndatums*sizeof(Datum*));
396+
boundinfo->ndatums=nparts;
397+
boundinfo->datums= (Datum**)palloc0(nparts*sizeof(Datum*));
398+
boundinfo->kind=NULL;
400399
boundinfo->nindexes=greatest_modulus;
401400
boundinfo->indexes= (int*)palloc(greatest_modulus*sizeof(int));
402401
for (i=0;i<greatest_modulus;i++)
403402
boundinfo->indexes[i]=-1;
404403

404+
/*
405+
* In the loop below, to save from allocating a series of small datum
406+
* arrays, here we just allocate a single array and below we'll just
407+
* assign a portion of this array per partition.
408+
*/
409+
boundDatums= (Datum*)palloc(nparts*2*sizeof(Datum));
410+
405411
/*
406412
* For hash partitioning, there are as many datums (modulus and remainder
407413
* pairs) as there are partitions. Indexes are simply values ranging from
408414
* 0 to (nparts - 1).
409415
*/
410416
for (i=0;i<nparts;i++)
411417
{
412-
intmodulus=hbounds[i]->modulus;
413-
intremainder=hbounds[i]->remainder;
418+
intmodulus=hbounds[i].modulus;
419+
intremainder=hbounds[i].remainder;
414420

415-
boundinfo->datums[i]=(Datum*)palloc(2*sizeof(Datum));
421+
boundinfo->datums[i]=&boundDatums[i*2];
416422
boundinfo->datums[i][0]=Int32GetDatum(modulus);
417423
boundinfo->datums[i][1]=Int32GetDatum(remainder);
418424

@@ -424,14 +430,39 @@ create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts,
424430
remainder+=modulus;
425431
}
426432

427-
(*mapping)[hbounds[i]->index]=i;
428-
pfree(hbounds[i]);
433+
(*mapping)[hbounds[i].index]=i;
429434
}
430435
pfree(hbounds);
431436

432437
returnboundinfo;
433438
}
434439

440+
/*
441+
* get_non_null_list_datum_count
442+
* Counts the number of non-null Datums in each partition.
443+
*/
444+
staticint
445+
get_non_null_list_datum_count(PartitionBoundSpec**boundspecs,intnparts)
446+
{
447+
inti;
448+
intcount=0;
449+
450+
for (i=0;i<nparts;i++)
451+
{
452+
ListCell*lc;
453+
454+
foreach(lc,boundspecs[i]->listdatums)
455+
{
456+
Const*val=castNode(Const,lfirst(lc));
457+
458+
if (!val->constisnull)
459+
count++;
460+
}
461+
}
462+
463+
returncount;
464+
}
465+
435466
/*
436467
* create_list_bounds
437468
*Create a PartitionBoundInfo for a list partitioned table
@@ -441,14 +472,14 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
441472
PartitionKeykey,int**mapping)
442473
{
443474
PartitionBoundInfoboundinfo;
444-
PartitionListValue**all_values=NULL;
445-
ListCell*cell;
446-
inti=0;
447-
intndatums=0;
475+
PartitionListValue*all_values;
476+
inti;
477+
intj;
478+
intndatums;
448479
intnext_index=0;
449480
intdefault_index=-1;
450481
intnull_index=-1;
451-
List*non_null_values=NIL;
482+
Datum*boundDatums;
452483

453484
boundinfo= (PartitionBoundInfoData*)
454485
palloc0(sizeof(PartitionBoundInfoData));
@@ -457,8 +488,12 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
457488
boundinfo->null_index=-1;
458489
boundinfo->default_index=-1;
459490

491+
ndatums=get_non_null_list_datum_count(boundspecs,nparts);
492+
all_values= (PartitionListValue*)
493+
palloc(ndatums*sizeof(PartitionListValue));
494+
460495
/* Create a unified list of non-null values across all partitions. */
461-
for (i=0;i<nparts;i++)
496+
for (j=0,i=0;i<nparts;i++)
462497
{
463498
PartitionBoundSpec*spec=boundspecs[i];
464499
ListCell*c;
@@ -480,14 +515,12 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
480515
foreach(c,spec->listdatums)
481516
{
482517
Const*val=castNode(Const,lfirst(c));
483-
PartitionListValue*list_value=NULL;
484518

485519
if (!val->constisnull)
486520
{
487-
list_value= (PartitionListValue*)
488-
palloc0(sizeof(PartitionListValue));
489-
list_value->index=i;
490-
list_value->value=val->constvalue;
521+
all_values[j].index=i;
522+
all_values[j].value=val->constvalue;
523+
j++;
491524
}
492525
else
493526
{
@@ -499,40 +532,28 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
499532
elog(ERROR,"found null more than once");
500533
null_index=i;
501534
}
502-
503-
if (list_value)
504-
non_null_values=lappend(non_null_values,list_value);
505535
}
506536
}
507537

508-
ndatums=list_length(non_null_values);
509-
510-
/*
511-
* Collect all list values in one array. Alongside the value, we also save
512-
* the index of partition the value comes from.
513-
*/
514-
all_values= (PartitionListValue**)
515-
palloc(ndatums*sizeof(PartitionListValue*));
516-
i=0;
517-
foreach(cell,non_null_values)
518-
{
519-
PartitionListValue*src=lfirst(cell);
520-
521-
all_values[i]= (PartitionListValue*)
522-
palloc(sizeof(PartitionListValue));
523-
all_values[i]->value=src->value;
524-
all_values[i]->index=src->index;
525-
i++;
526-
}
538+
/* ensure we found a Datum for every slot in the all_values array */
539+
Assert(j==ndatums);
527540

528-
qsort_arg(all_values,ndatums,sizeof(PartitionListValue*),
541+
qsort_arg(all_values,ndatums,sizeof(PartitionListValue),
529542
qsort_partition_list_value_cmp, (void*)key);
530543

531544
boundinfo->ndatums=ndatums;
532545
boundinfo->datums= (Datum**)palloc0(ndatums*sizeof(Datum*));
546+
boundinfo->kind=NULL;
533547
boundinfo->nindexes=ndatums;
534548
boundinfo->indexes= (int*)palloc(ndatums*sizeof(int));
535549

550+
/*
551+
* In the loop below, to save from allocating a series of small datum
552+
* arrays, here we just allocate a single array and below we'll just
553+
* assign a portion of this array per datum.
554+
*/
555+
boundDatums= (Datum*)palloc(ndatums*sizeof(Datum));
556+
536557
/*
537558
* Copy values. Canonical indexes are values ranging from 0 to (nparts -
538559
* 1) assigned to each partition such that all datums of a given partition
@@ -541,10 +562,10 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
541562
*/
542563
for (i=0;i<ndatums;i++)
543564
{
544-
intorig_index=all_values[i]->index;
565+
intorig_index=all_values[i].index;
545566

546-
boundinfo->datums[i]=(Datum*)palloc(sizeof(Datum));
547-
boundinfo->datums[i][0]=datumCopy(all_values[i]->value,
567+
boundinfo->datums[i]=&boundDatums[i];
568+
boundinfo->datums[i][0]=datumCopy(all_values[i].value,
548569
key->parttypbyval[0],
549570
key->parttyplen[0]);
550571

@@ -555,6 +576,8 @@ create_list_bounds(PartitionBoundSpec **boundspecs, int nparts,
555576
boundinfo->indexes[i]= (*mapping)[orig_index];
556577
}
557578

579+
pfree(all_values);
580+
558581
/*
559582
* Set the canonical value for null_index, if any.
560583
*
@@ -603,10 +626,13 @@ create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
603626
PartitionRangeBound**all_bounds,
604627
*prev;
605628
inti,
606-
k;
629+
k,
630+
partnatts;
607631
intndatums=0;
608632
intdefault_index=-1;
609633
intnext_index=0;
634+
Datum*boundDatums;
635+
PartitionRangeDatumKind*boundKinds;
610636

611637
boundinfo= (PartitionBoundInfoData*)
612638
palloc0(sizeof(PartitionBoundInfoData));
@@ -707,6 +733,8 @@ create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
707733
prev=cur;
708734
}
709735

736+
pfree(all_bounds);
737+
710738
/* Update ndatums to hold the count of distinct datums. */
711739
ndatums=k;
712740

@@ -731,16 +759,24 @@ create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
731759
boundinfo->nindexes=ndatums+1;
732760
boundinfo->indexes= (int*)palloc((ndatums+1)*sizeof(int));
733761

762+
/*
763+
* In the loop below, to save from allocating a series of small arrays,
764+
* here we just allocate a single array for Datums and another for
765+
* PartitionRangeDatumKinds, below we'll just assign a portion of these
766+
* arrays in each loop.
767+
*/
768+
partnatts=key->partnatts;
769+
boundDatums= (Datum*)palloc(ndatums*partnatts*sizeof(Datum));
770+
boundKinds= (PartitionRangeDatumKind*)palloc(ndatums*partnatts*
771+
sizeof(PartitionRangeDatumKind));
772+
734773
for (i=0;i<ndatums;i++)
735774
{
736775
intj;
737776

738-
boundinfo->datums[i]= (Datum*)palloc(key->partnatts*
739-
sizeof(Datum));
740-
boundinfo->kind[i]= (PartitionRangeDatumKind*)
741-
palloc(key->partnatts*
742-
sizeof(PartitionRangeDatumKind));
743-
for (j=0;j<key->partnatts;j++)
777+
boundinfo->datums[i]=&boundDatums[i*partnatts];
778+
boundinfo->kind[i]=&boundKinds[i*partnatts];
779+
for (j=0;j<partnatts;j++)
744780
{
745781
if (rbounds[i]->kind[j]==PARTITION_RANGE_DATUM_VALUE)
746782
boundinfo->datums[i][j]=
@@ -772,6 +808,8 @@ create_range_bounds(PartitionBoundSpec **boundspecs, int nparts,
772808
}
773809
}
774810

811+
pfree(rbounds);
812+
775813
/* Set the canonical value for default_index, if any. */
776814
if (default_index!=-1)
777815
{
@@ -914,6 +952,7 @@ partition_bounds_copy(PartitionBoundInfo src,
914952
intpartnatts;
915953
boolhash_part;
916954
intnatts;
955+
Datum*boundDatums;
917956

918957
dest= (PartitionBoundInfo)palloc(sizeof(PartitionBoundInfoData));
919958

@@ -929,15 +968,27 @@ partition_bounds_copy(PartitionBoundInfo src,
929968

930969
if (src->kind!=NULL)
931970
{
971+
PartitionRangeDatumKind*boundKinds;
972+
973+
/* only RANGE partition should have a non-NULL kind */
974+
Assert(key->strategy==PARTITION_STRATEGY_RANGE);
975+
932976
dest->kind= (PartitionRangeDatumKind**)palloc(ndatums*
933977
sizeof(PartitionRangeDatumKind*));
978+
979+
/*
980+
* In the loop below, to save from allocating a series of small arrays
981+
* for storing the PartitionRangeDatumKind, we allocate a single chunk
982+
* here and use a smaller portion of it for each datum.
983+
*/
984+
boundKinds= (PartitionRangeDatumKind*)palloc(ndatums*partnatts*
985+
sizeof(PartitionRangeDatumKind));
986+
934987
for (i=0;i<ndatums;i++)
935988
{
936-
dest->kind[i]= (PartitionRangeDatumKind*)palloc(partnatts*
937-
sizeof(PartitionRangeDatumKind));
938-
989+
dest->kind[i]=&boundKinds[i*partnatts];
939990
memcpy(dest->kind[i],src->kind[i],
940-
sizeof(PartitionRangeDatumKind)*key->partnatts);
991+
sizeof(PartitionRangeDatumKind)*partnatts);
941992
}
942993
}
943994
else
@@ -949,12 +1000,13 @@ partition_bounds_copy(PartitionBoundInfo src,
9491000
*/
9501001
hash_part= (key->strategy==PARTITION_STRATEGY_HASH);
9511002
natts=hash_part ?2 :partnatts;
1003+
boundDatums=palloc(ndatums*natts*sizeof(Datum));
9521004

9531005
for (i=0;i<ndatums;i++)
9541006
{
9551007
intj;
9561008

957-
dest->datums[i]=(Datum*)palloc(sizeof(Datum)*natts);
1009+
dest->datums[i]=&boundDatums[i*natts];
9581010

9591011
for (j=0;j<natts;j++)
9601012
{
@@ -3682,8 +3734,8 @@ partition_hash_bsearch(PartitionBoundInfo boundinfo,
36823734
staticint32
36833735
qsort_partition_hbound_cmp(constvoid*a,constvoid*b)
36843736
{
3685-
PartitionHashBound*h1= (*(PartitionHashBound*const*)a);
3686-
PartitionHashBound*h2= (*(PartitionHashBound*const*)b);
3737+
PartitionHashBound*consth1= (PartitionHashBound*const)a;
3738+
PartitionHashBound*consth2= (PartitionHashBound*const)b;
36873739

36883740
returnpartition_hbound_cmp(h1->modulus,h1->remainder,
36893741
h2->modulus,h2->remainder);
@@ -3697,8 +3749,8 @@ qsort_partition_hbound_cmp(const void *a, const void *b)
36973749
staticint32
36983750
qsort_partition_list_value_cmp(constvoid*a,constvoid*b,void*arg)
36993751
{
3700-
Datumval1= (*(PartitionListValue*const*)a)->value,
3701-
val2= (*(PartitionListValue*const*)b)->value;
3752+
Datumval1= ((PartitionListValue*const)a)->value,
3753+
val2= ((PartitionListValue*const)b)->value;
37023754
PartitionKeykey= (PartitionKey)arg;
37033755

37043756
returnDatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp