8000 Add optimizer and executor support for parallel index-only scans. · intobs/postgres@0414b26 · GitHub
[go: up one dir, main page]

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)
0