Skip to content

Commit 0414b26

Browse files
committed
Add optimizer and executor support for parallel index-only scans.
Commit 5262f7a added similar support for parallel index scans; this extends that work to index-only scans. As with parallel index scans, this requires support from the index AM, so currently parallel index-only scans will only be possible for btree indexes. Rafia Sabih, reviewed and tested by Rahila Syed, Tushar Ahuja, and Amit Kapila Discussion: http://postgr.es/m/CAOGQiiPEAs4C=TBp0XShxBvnWXuzGL2u++Hm1=qnCpd6_Mf8Fw@mail.gmail.com
1 parent 16be2fd commit 0414b26

File tree

7 files changed

+191
-26
lines changed

7 files changed

+191
-26
lines changed

src/backend/executor/execParallel.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "executor/nodeForeignscan.h"
3030
#include "executor/nodeSeqscan.h"
3131
#include "executor/nodeIndexscan.h"
32+
#include "executor/nodeIndexonlyscan.h"
3233
#include "executor/tqueue.h"
3334
#include "nodes/nodeFuncs.h"
3435
#include "optimizer/planmain.h"
@@ -202,6 +203,10 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
202203
ExecIndexScanEstimate((IndexScanState *) planstate,
203204
e->pcxt);
204205
break;
206+
case T_IndexOnlyScanState:
207+
ExecIndexOnlyScanEstimate((IndexOnlyScanState *) planstate,
208+
e->pcxt);
209+
break;
205210
case T_ForeignScanState:
206211
ExecForeignScanEstimate((ForeignScanState *) planstate,
207212
e->pcxt);
@@ -258,6 +263,10 @@ ExecParallelInitializeDSM(PlanState *planstate,
258263
ExecIndexScanInitializeDSM((IndexScanState *) planstate,
259264
d->pcxt);
260265
break;
266+
case T_IndexOnlyScanState:
267+
ExecIndexOnlyScanInitializeDSM((IndexOnlyScanState *) planstate,
268+
d->pcxt);
269+
break;
261270
case T_ForeignScanState:
262271
ExecForeignScanInitializeDSM((ForeignScanState *) planstate,
263272
d->pcxt);
@@ -737,6 +746,9 @@ ExecParallelInitializeWorker(PlanState *planstate, shm_toc *toc)
737746
case T_IndexScanState:
738747
ExecIndexScanInitializeWorker((IndexScanState *) planstate, toc);
739748
break;
749+
case T_IndexOnlyScanState:
750+
ExecIndexOnlyScanInitializeWorker((IndexOnlyScanState *) planstate, toc);
751+
break;
740752
case T_ForeignScanState:
741753
ExecForeignScanInitializeWorker((ForeignScanState *) planstate,
742754
toc);

src/backend/executor/nodeIndexonlyscan.c

Lines changed: 135 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
* ExecEndIndexOnlyScan releases all storage.
2222
* ExecIndexOnlyMarkPos marks scan position.
2323
* ExecIndexOnlyRestrPos restores scan position.
24+
* ExecIndexOnlyScanEstimate estimates DSM space needed for
25+
* parallel index-only scan
26+
* ExecIndexOnlyScanInitializeDSM initialize DSM for parallel
27+
* index-only scan
28+
* ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
2429
*/
2530
#include "postgres.h"
2631

@@ -277,6 +282,16 @@ ExecIndexOnlyScan(IndexOnlyScanState *node)
277282
void
278283
ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
279284
{
285+
bool reset_parallel_scan = true;
286+
287+
/*
288+
* If we are here to just update the scan keys, then don't reset parallel
289+
* scan. For detailed reason behind this look in the comments for
290+
* ExecReScanIndexScan.
291+
*/
292+
if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
293+
reset_parallel_scan = false;
294+
280295
/*
281296
* If we are doing runtime key calculations (ie, any of the index key
282297
* values weren't simple Consts), compute the new key values. But first,
@@ -296,10 +311,16 @@ ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
296311
node->ioss_RuntimeKeysReady = true;
297312

298313
/* reset index scan */
299-
index_rescan(node->ioss_ScanDesc,
300-
node->ioss_ScanKeys, node->ioss_NumScanKeys,
301-
node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
314+
if (node->ioss_ScanDesc)
315+
{
316+
317+
index_rescan(node->ioss_ScanDesc,
318+
node->ioss_ScanKeys, node->ioss_NumScanKeys,
319+
node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
302320

321+
if (reset_parallel_scan && node->ioss_ScanDesc->parallel_scan)
322+
index_parallelrescan(node->ioss_ScanDesc);
323+
}
303324
ExecScanReScan(&node->ss);
304325
}
305326

@@ -536,29 +557,124 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
536557
/*
537558
* Initialize scan descriptor.
538559
*/
539-
indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
540-
indexstate->ioss_RelationDesc,
541-
estate->es_snapshot,
560+
if (!node->scan.plan.parallel_aware)
561+
{
562+
indexstate->ioss_ScanDesc = index_beginscan(currentRelation,
563+
indexstate->ioss_RelationDesc,
564+
estate->es_snapshot,
542565
indexstate->ioss_NumScanKeys,
543566
indexstate->ioss_NumOrderByKeys);
544567

545-
/* Set it up for index-only scan */
546-
indexstate->ioss_ScanDesc->xs_want_itup = true;
547-
indexstate->ioss_VMBuffer = InvalidBuffer;
548568

549-
/*
550-
* If no run-time keys to calculate, go ahead and pass the scankeys to the
551-
* index AM.
552-
*/
553-
if (indexstate->ioss_NumRuntimeKeys == 0)
554-
index_rescan(indexstate->ioss_ScanDesc,
555-
indexstate->ioss_ScanKeys,
556-
indexstate->ioss_NumScanKeys,
557-
indexstate->ioss_OrderByKeys,
558-
indexstate->ioss_NumOrderByKeys);
569+
/* Set it up for index-only scan */
570+
indexstate->ioss_ScanDesc->xs_want_itup = true;
571+
indexstate->ioss_VMBuffer = InvalidBuffer;
572+
573+
/*
574+
* If no run-time keys to calculate, go ahead and pass the scankeys to
575+
* the index AM.
576+
*/
577+
if (indexstate->ioss_NumRuntimeKeys == 0)
578+
index_rescan(indexstate->ioss_ScanDesc,
579+
indexstate->ioss_ScanKeys,
580+
indexstate->ioss_NumScanKeys,
581+
indexstate->ioss_OrderByKeys,
582+
indexstate->ioss_NumOrderByKeys);
583+
}
559584

560585
/*
561586
* all done.
562587
*/
563588
return indexstate;
564589
}
590+
591+
/* ----------------------------------------------------------------
592+
* Parallel Index-only Scan Support
593+
* ----------------------------------------------------------------
594+
*/
595+
596+
/* ----------------------------------------------------------------
597+
* ExecIndexOnlyScanEstimate
598+
*
599+
* estimates the space required to serialize index-only scan node.
600+
* ----------------------------------------------------------------
601+
*/
602+
void
603+
ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
604+
ParallelContext *pcxt)
605+
{
606+
EState *estate = node->ss.ps.state;
607+
608+
node->ioss_PscanLen = index_parallelscan_estimate(node->ioss_RelationDesc,
609+
estate->es_snapshot);
610+
shm_toc_estimate_chunk(&pcxt->estimator, node->ioss_PscanLen);
611+
shm_toc_estimate_keys(&pcxt->estimator, 1);
612+
}
613+
614+
/* ----------------------------------------------------------------
615+
* ExecIndexOnlyScanInitializeDSM
616+
*
617+
* Set up a parallel index-only scan descriptor.
618+
* ----------------------------------------------------------------
619+
*/
620+
void
621+
ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
622+
ParallelContext *pcxt)
623+
{
624+
EState *estate = node->ss.ps.state;
625+
ParallelIndexScanDesc piscan;
626+
627+
piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
628+
index_parallelscan_initialize(node->ss.ss_currentRelation,
629+
node->ioss_RelationDesc,
630+
estate->es_snapshot,
631+
piscan);
632+
shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
633+
node->ioss_ScanDesc =
634+
index_beginscan_parallel(node->ss.ss_currentRelation,
635+
node->ioss_RelationDesc,
636+
node->ioss_NumScanKeys,
637+
node->ioss_NumOrderByKeys,
638+
piscan);
639+
node->ioss_ScanDesc->xs_want_itup = true;
640+
node->ioss_VMBuffer = InvalidBuffer;
641+
642+
/*
643+
* If no run-time keys to calculate, go ahead and pass the scankeys to
644+
* the index AM.
645+
*/
646+
if (node->ioss_NumRuntimeKeys == 0)
647+
index_rescan(node->ioss_ScanDesc,
648+
node->ioss_ScanKeys, node->ioss_NumScanKeys,
649+
node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
650+
}
651+
652+
/* ----------------------------------------------------------------
653+
* ExecIndexOnlyScanInitializeWorker
654+
*
655+
* Copy relevant information from TOC into planstate.
656+
* ----------------------------------------------------------------
657+
*/
658+
void
659+
ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, shm_toc *toc)
660+
{
661+
ParallelIndexScanDesc piscan;
662+
663+
piscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id);
664+
node->ioss_ScanDesc =
665+
index_beginscan_parallel(node->ss.ss_currentRelation,
666+
node->ioss_RelationDesc,
667+
node->ioss_NumScanKeys,
668+
node->ioss_NumOrderByKeys,
669+
piscan);
670+
node->ioss_ScanDesc->xs_want_itup = true;
671+
672+
/*
673+
* If no run-time keys to calculate, go ahead and pass the scankeys to the
674+
* index AM.
675+
*/
676+
if (node->ioss_NumRuntimeKeys == 0)
677+
index_rescan(node->ioss_ScanDesc,
678+
node->ioss_ScanKeys, node->ioss_NumScanKeys,
679+
node->ioss_OrderByKeys, node->ioss_NumOrderByKeys);
680+
}

src/backend/optimizer/path/indxpath.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,9 +1048,9 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
10481048

10491049
/*
10501050
* If appropriate, consider parallel index scan. We don't allow
1051-
* parallel index scan for bitmap or index only scans.
1051+
* parallel index scan for bitmap index scans.
10521052
*/
1053-
if (index->amcanparallel && !index_only_scan &&
1053+
if (index->amcanparallel &&
10541054
rel->consider_parallel && outer_relids == NULL &&
10551055
scantype != ST_BITMAPSCAN)
10561056
{
@@ -1104,7 +1104,7 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel,
11041104
result = lappend(result, ipath);
11051105

11061106
/* If appropriate, consider parallel index scan */
1107-
if (index->amcanparallel && !index_only_scan &&
1107+
if (index->amcanparallel &&
11081108
rel->consider_parallel && outer_relids == NULL &&
11091109
scantype != ST_BITMAPSCAN)
11101110
{

src/include/executor/nodeIndexonlyscan.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define NODEINDEXONLYSCAN_H
1616

1717
#include "nodes/execnodes.h"
18+
#include "access/parallel.h"
1819

1920
extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
2021
extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
@@ -23,4 +24,12 @@ extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
2324
extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
2425
extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node);
2526

27+
/* Support functions for parallel index-only scans */
28+
extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node,
29+
ParallelContext *pcxt);
30+
extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node,
31+
ParallelContext *pcxt);
32+
extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node,
33+
shm_toc *toc);
34+
2635
#endif /* NODEINDEXONLYSCAN_H */

src/include/nodes/execnodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,7 @@ typedef struct IndexScanState
14091409
* ScanDesc index scan descriptor
14101410
* VMBuffer buffer in use for visibility map testing, if any
14111411
* HeapFetches number of tuples we were forced to fetch from heap
1412+
* ioss_PscanLen Size of parallel index-only scan descriptor
14121413
* ----------------
14131414
*/
14141415
typedef struct IndexOnlyScanState
@@ -1427,6 +1428,7 @@ typedef struct IndexOnlyScanState
14271428
IndexScanDesc ioss_ScanDesc;
14281429
Buffer ioss_VMBuffer;
14291430
long ioss_HeapFetches;
1431+
Size ioss_PscanLen;
14301432
} IndexOnlyScanState;
14311433

14321434
/* ----------------

src/test/regress/expected/select_parallel.out

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,14 @@ explain (costs off)
9292
explain (costs off)
9393
select sum(parallel_restricted(unique1)) from tenk1
9494
group by(parallel_restricted(unique1));
95-
QUERY PLAN
96-
----------------------------------------------------
95+
QUERY PLAN
96+
-------------------------------------------------------------------
9797
HashAggregate
9898
Group Key: parallel_restricted(unique1)
99-
-> Index Only Scan using tenk1_unique1 on tenk1
100-
(3 rows)
99+
-> Gather
100+
Workers Planned: 4
101+
-> Parallel Index Only Scan using tenk1_unique1 on tenk1
102+
(5 rows)
101103

102104
-- test parallel plans for queries containing un-correlated subplans.
103105
alter table tenk2 set (parallel_workers = 0);
@@ -146,6 +148,25 @@ select count((unique1)) from tenk1 where hundred > 1;
146148
9800
147149
(1 row)
148150

151+
-- test parallel index-only scans.
152+
explain (costs off)
153+
select count(*) from tenk1 where thousand > 95;
154+
QUERY PLAN
155+
--------------------------------------------------------------------------------
156+
Finalize Aggregate
157+
-> Gather
158+
Workers Planned: 4
159+
-> Partial Aggregate
160+
-> Parallel Index Only Scan using tenk1_thous_tenthous on tenk1
161+
Index Cond: (thousand > 95)
162+
(6 rows)
163+
164+
select count(*) from tenk1 where thousand > 95;
165+
count
166+
-------
167+
9040
168+
(1 row)
169+
149170
reset enable_seqscan;
150171
reset enable_bitmapscan;
151172
set force_parallel_mode=1;

src/test/regress/sql/select_parallel.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ explain (costs off)
5656
select count((unique1)) from tenk1 where hundred > 1;
5757
select count((unique1)) from tenk1 where hundred > 1;
5858

59+
-- test parallel index-only scans.
60+
explain (costs off)
61+
select count(*) from tenk1 where thousand > 95;
62+
select count(*) from tenk1 where thousand > 95;
63+
5964
reset enable_seqscan;
6065
reset enable_bitmapscan;
6166

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy