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

Commitb027861

Browse files
committed
Tune costs of nodeCustomTempScan: use analogy with Append.
1 parent7e13f7d commitb027861

File tree

3 files changed

+133
-117
lines changed

3 files changed

+133
-117
lines changed

‎contrib/tempscan/expected/basic.out

Lines changed: 55 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,15 @@ SELECT count(*) FROM parallel_test;
2828
-> Parallel Seq Scan on parallel_test
2929
(5 rows)
3030

31-
-- Should also utilise parallel workers like scanning of a plain table
31+
-- Do not use parallel scan of temporary table so far. As a result, shouldn't
32+
-- find nodeCustomTempScan here
3233
EXPLAIN (COSTS OFF)
3334
SELECT count(*) FROM parallel_test_tmp;
34-
QUERY PLAN
35-
----------------------------------------------------------------
36-
Finalize Aggregate
37-
-> Gather
38-
Workers Planned: 1
39-
-> Partial Aggregate
40-
-> Custom Scan (nodeCustomTempScan)
41-
-> Parallel Seq Scan on parallel_test_tmp
42-
(6 rows)
35+
QUERY PLAN
36+
-------------------------------------
37+
Aggregate
38+
-> Seq Scan on parallel_test_tmp
39+
(2 rows)
4340

4441
-- Want to see here partial aggregate over parallel join
4542
EXPLAIN (COSTS OFF)
@@ -59,18 +56,18 @@ SELECT count(*) FROM parallel_test t1 NATURAL JOIN parallel_test t2;
5956

6057
EXPLAIN (COSTS OFF)
6158
SELECT count(*) FROM parallel_test_tmp t1 NATURAL JOIN parallel_test t2;
62-
QUERY PLAN
63-
-------------------------------------------------------------------------
59+
QUERY PLAN
60+
----------------------------------------------------------------------
6461
Finalize Aggregate
6562
-> Gather
6663
Workers Planned: 1
6764
-> Partial Aggregate
68-
->ParallelHash Join
69-
Hash Cond: (t1.x =t2.x)
70-
->CustomScan(nodeCustomTempScan)
71-
->Parallel Seq Scan on parallel_test_tmp t1
72-
->Parallel Hash
73-
->ParallelSeq Scan onparallel_test t2
65+
-> Hash Join
66+
Hash Cond: (t2.x =t1.x)
67+
->Parallel SeqScanon parallel_test t2
68+
->Hash
69+
->Custom Scan (nodeCustomTempScan)
70+
-> Seq Scan onparallel_test_tmp t1
7471
(10 rows)
7572

7673
-- Just see how merge join manages custom parallel scan path
@@ -95,100 +92,81 @@ SELECT count(*) FROM parallel_test t1 NATURAL JOIN parallel_test t2;
9592

9693
EXPLAIN (COSTS OFF)
9794
SELECT count(*) FROM parallel_test_tmp t1 NATURAL JOIN parallel_test t2;
98-
QUERY PLAN
99-
-------------------------------------------------------------------------------
95+
QUERY PLAN
96+
----------------------------------------------------------------------
10097
Finalize Aggregate
10198
-> Gather
10299
Workers Planned: 1
103100
-> Partial Aggregate
104101
-> Merge Join
105-
Merge Cond: (t1.x = t2.x)
102+
Merge Cond: (t2.x = t1.x)
103+
-> Sort
104+
Sort Key: t2.x
105+
-> Parallel Seq Scan on parallel_test t2
106106
-> Sort
107107
Sort Key: t1.x
108108
-> Custom Scan (nodeCustomTempScan)
109-
-> Parallel Seq Scan on parallel_test_tmp t1
110-
-> Sort
111-
Sort Key: t2.x
112-
-> Seq Scan on parallel_test t2
109+
-> Seq Scan on parallel_test_tmp t1
113110
(13 rows)
114111

115112
RESET enable_hashjoin;
116113
-- Increase table size and see how indexes work
117114
ALTER TABLE parallel_test ADD COLUMN y text DEFAULT 'none';
118115
INSERT INTO parallel_test (x,y) SELECT x, 'data' || x AS y FROM generate_series(1,10000) AS x;
119-
CREATE INDEX ON parallel_test (x);
120-
ANALYZE parallel_test;
116+
CREATE INDEX ON parallel_test_tmp (x);
117+
VACUUM ANALYZE;
118+
-- Use IndexScan on temporary table
121119
EXPLAIN (COSTS OFF)
122-
SELECT count(*) FROM parallel_test t1 NATURAL JOINparallel_test t2
120+
SELECT count(*) FROM parallel_test t1 NATURAL JOINparallel_test_tmp t2
123121
WHERE t1.x < 10;
124-
QUERY PLAN
125-
-------------------------------------------------------------------------------------
122+
QUERY PLAN
123+
-----------------------------------------------------------------------------------------------
126124
Aggregate
127125
-> Gather
128-
Workers Planned:1
126+
Workers Planned:3
129127
-> Nested Loop
130-
-> ParallelIndex Scan using parallel_test_x_idx on parallel_test t1
131-
Index Cond: (x < 10)
132-
->Index Scanusing parallel_test_x_idx on parallel_test t2
133-
IndexCond: (x = t1.x)
134-
Filter: (y = t1.y)
128+
-> ParallelSeq Scan on parallel_test t1
129+
Filter: (x < 10)
130+
->Custom Scan(nodeCustomTempScan)
131+
->IndexOnly Scan using parallel_test_tmp_x_idx on parallel_test_tmp t2
132+
Index Cond: (x = t1.x)
135133
(9 rows)
136134

137-
EXPLAIN (COSTS OFF)
138-
SELECT count(*) FROM parallel_test t1 NATURAL JOIN parallel_test_tmp t2
139-
WHERE t1.x < 10;
140-
QUERY PLAN
141-
---------------------------------------------------------------------------------
142-
Aggregate
143-
-> Gather
144-
Workers Planned: 1
145-
-> Merge Join
146-
Merge Cond: (t2.x = t1.x)
147-
-> Sort
148-
Sort Key: t2.x
149-
-> Custom Scan (nodeCustomTempScan)
150-
-> Parallel Seq Scan on parallel_test_tmp t2
151-
-> Index Only Scan using parallel_test_x_idx on parallel_test t1
152-
Index Cond: (x < 10)
153-
(11 rows)
154-
155135
CREATE TEMP TABLE parallel_test_tmp_2 AS (SELECT * FROM parallel_test);
156136
CREATE INDEX ON parallel_test_tmp_2 (x);
157-
ANALYZE parallel_test_tmp_2;
137+
VACUUM ANALYZE;
138+
-- Can't use parallel workers here: for now temp tables can be used as parallel
139+
-- safe source but not be read concurrently.
158140
EXPLAIN (COSTS OFF)
159141
SELECT count(*) FROM parallel_test_tmp t1 NATURAL JOIN parallel_test_tmp_2 t2
160142
WHERE t2.x < 10;
161-
QUERY PLAN
162-
---------------------------------------------------------------------------------------------
143+
QUERY PLAN
144+
---------------------------------------------------------------------------------------
163145
Aggregate
164-
-> Gather
165-
Workers Planned: 1
166-
-> Merge Join
167-
Merge Cond: (t1.x = t2.x)
168-
-> Sort
169-
Sort Key: t1.x
170-
-> Custom Scan (nodeCustomTempScan)
171-
-> Parallel Seq Scan on parallel_test_tmp t1
172-
-> Index Only Scan using parallel_test_tmp_2_x_idx on parallel_test_tmp_2 t2
173-
Index Cond: (x < 10)
174-
(11 rows)
146+
-> Merge Join
147+
Merge Cond: (t1.x = t2.x)
148+
-> Sort
149+
Sort Key: t1.x
150+
-> Seq Scan on parallel_test_tmp t1
151+
-> Index Only Scan using parallel_test_tmp_2_x_idx on parallel_test_tmp_2 t2
152+
Index Cond: (x < 10)
153+
(8 rows)
175154

176155
EXPLAIN (COSTS OFF)
177156
SELECT count(*) FROM parallel_test_tmp_2 t1 NATURAL JOIN parallel_test_tmp_2 t2
178157
WHERE t1.x < 10;
179-
QUERY PLAN
180-
-------------------------------------------------------------------------------------------------------
158+
QUERY PLAN
159+
----------------------------------------------------------------------------------------
181160
Aggregate
182-
-> Gather
183-
Workers Planned: 1
184-
-> Nested Loop
185-
-> Custom Scan (nodeCustomTempScan)
186-
-> Parallel Index Scan using parallel_test_tmp_2_x_idx on parallel_test_tmp_2 t1
187-
Index Cond: (x < 10)
161+
-> Nested Loop
162+
-> Custom Scan (nodeCustomTempScan)
163+
-> Index Scan using parallel_test_tmp_2_x_idx on parallel_test_tmp_2 t1
164+
Index Cond: (x < 10)
165+
-> Custom Scan (nodeCustomTempScan)
188166
-> Index Scan using parallel_test_tmp_2_x_idx on parallel_test_tmp_2 t2
189167
Index Cond: (x = t1.x)
190168
Filter: (y = t1.y)
191-
(10 rows)
169+
(9 rows)
192170

193171
RESET tempscan.enable;
194172
DROP TABLE parallel_test, parallel_test_tmp;

‎contrib/tempscan/nodeCustomTempScan.c

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include"nodes/extensible.h"
1717
#include"optimizer/clauses.h"
1818
#include"optimizer/cost.h"
19+
#include"optimizer/optimizer.h"
1920
#include"optimizer/pathnode.h"
2021
#include"optimizer/paths.h"
2122
#include"utils/guc.h"
@@ -27,6 +28,9 @@ PG_MODULE_MAGIC;
2728
#defineMODULENAME"tempscan"
2829
#defineNODENAME"nodeCustomTempScan"
2930

31+
/* By analogy with Append */
32+
#defineTEMPSCAN_CPU_COST_MULTIPLIER(0.5)
33+
3034
staticPlan*create_partial_tempscan_plan(PlannerInfo*root,
3135
RelOptInfo*rel,
3236
CustomPath*best_path,
@@ -38,6 +42,7 @@ static void BeginTempScan(CustomScanState *node, EState *estate, int eflags);
3842
staticTupleTableSlot*ExecTempScan(CustomScanState*node);
3943
staticvoidEndTempScan(CustomScanState*node);
4044
staticvoidReScanTempScan(CustomScanState*node);
45+
staticSizeEstimateDSMTempScan(CustomScanState*node,ParallelContext*pcxt);
4146

4247
staticCustomPathMethodspath_methods=
4348
{
@@ -62,7 +67,7 @@ static CustomExecMethods exec_methods =
6267
.ReScanCustomScan=ReScanTempScan,
6368
.MarkPosCustomScan=NULL,
6469
.RestrPosCustomScan=NULL,
65-
.EstimateDSMCustomScan=NULL,
70+
.EstimateDSMCustomScan=EstimateDSMTempScan,
6671
.InitializeDSMCustomScan=NULL,
6772
.ReInitializeDSMCustomScan=NULL,
6873
.InitializeWorkerCustomScan=NULL,
@@ -93,18 +98,22 @@ create_partial_tempscan_path(PlannerInfo *root, RelOptInfo *rel,
9398
pathnode->parent=rel;
9499
pathnode->pathtarget=rel->reltarget;
95100
pathnode->rows=path->rows;/* Don't use rel->rows! Remember semantics of this field in the parallel case */
96-
97-
/* XXX: Just for now */
98-
pathnode->param_info=NULL;
101+
pathnode->param_info=path->param_info;
99102

100103
pathnode->parallel_safe= true;
101104
pathnode->parallel_aware= false;
102105
pathnode->parallel_workers=path->parallel_workers;
103106

104-
/* DEBUGGING purposes only */
105107
pathnode->startup_cost=path->startup_cost;
106108
pathnode->total_cost=path->total_cost;
107109

110+
/*
111+
* Although TempScan does not do any selection or projection, it's not free;
112+
* add a small per-tuple overhead.
113+
*/
114+
pathnode->total_cost+=
115+
cpu_tuple_cost*TEMPSCAN_CPU_COST_MULTIPLIER*path->rows;
116+
108117
cpath->custom_paths=list_make1(path);
109118
cpath->custom_private=NIL;
110119
cpath->custom_restrictinfo=NIL;
@@ -121,8 +130,7 @@ create_partial_tempscan_plan(PlannerInfo *root, RelOptInfo *rel,
121130
CustomScan*cscan=makeNode(CustomScan);
122131

123132
Assert(list_length(custom_plans)==1);
124-
Assert(best_path->path.parallel_safe= true&&
125-
best_path->path.parallel_workers>0);
133+
Assert(best_path->path.parallel_safe= true);
126134

127135

128136
cscan->scan.plan.targetlist=cscan->custom_scan_tlist=tlist;
@@ -205,9 +213,9 @@ static void
205213
try_partial_tempscan(PlannerInfo*root,RelOptInfo*rel,Indexrti,
206214
RangeTblEntry*rte)
207215
{
208-
intparallel_workers;
209216
ListCell*lc;
210-
List*partial_pathlist_new=NIL;
217+
List*parallel_safe_lst=NIL;
218+
List*tmplst=rel->pathlist;
211219

212220
/*
213221
* Some extension intercept this hook earlier. Allow it to do a work
@@ -223,46 +231,56 @@ try_partial_tempscan(PlannerInfo *root, RelOptInfo *rel, Index rti,
223231
get_rel_persistence(rte->relid)!=RELPERSISTENCE_TEMP)
224232
return;
225233

226-
/* HACK */
227234
if (!is_parallel_safe(root, (Node*)rel->baserestrictinfo)||
228235
!is_parallel_safe(root, (Node*)rel->reltarget->exprs))
229236
return;
230237

231-
parallel_workers=compute_parallel_worker(rel,rel->pages,-1,
232-
max_parallel_workers_per_gather);
233-
234-
/* If any limit was set to zero, the user doesn't want a parallel scan. */
235-
if (parallel_workers <=0)
236-
return;
237-
238-
/* Enable parallel paths generation for this relation */
238+
/* Enable parallel safe paths generation for this relation */
239239
Assert(rel->partial_pathlist==NIL);
240240
rel->consider_parallel= true;
241241

242-
/* Add partial sequental scan path. */
243-
add_partial_path(rel, (Path*)
244-
create_seqscan_path(root,rel,NULL,parallel_workers));
242+
/*
243+
* Now we have a problem:
244+
* should generate parallel safe paths. But they will have the same cost as
245+
* previously added non-parallel ones and, being safe, will definitely crowd
246+
* out non-safe ones.
247+
* So, we need a HACK: add new safe paths with cost of custom node.
248+
*/
245249

246-
/* Add there more specific paths too */
250+
rel->pathlist=NIL;
251+
252+
/*
253+
* Build possibly parallel paths other temporary table
254+
*/
255+
add_path(rel,create_seqscan_path(root,rel,NULL,0));
247256
create_index_paths(root,rel);
248257
create_tidscan_paths(root,rel);
249258

250-
foreach(lc,rel->partial_pathlist)
251-
{
252-
Path*path=lfirst(lc);
259+
/*
260+
* Dangerous zone. But we assume it is strictly local. What about extension
261+
* which could call ours and may have desire to add some partial paths after
262+
* us?
263+
*/
253264

254-
partial_pathlist_new=
255-
lappend(partial_pathlist_new,
256-
(void*)create_partial_tempscan_path(root,rel,path));
257-
}
265+
list_free(rel->partial_pathlist);
266+
rel->partial_pathlist=NIL;
258267

259268
/*
260-
* Dangerous zone. But we assume it is strictly local. What about extension
261-
* which could call ours and add some paths after us?
269+
* Set guard over each parallel_safe path
262270
*/
263-
rel->partial_pathlist=partial_pathlist_new;
271+
parallel_safe_lst=rel->pathlist;
272+
rel->pathlist=tmplst;
273+
foreach(lc,parallel_safe_lst)
274+
{
275+
Path*path=lfirst(lc);
276+
277+
if (!path->parallel_safe)
278+
continue;
279+
280+
add_path(rel, (Path*)create_partial_tempscan_path(root,rel,path));
281+
}
264282

265-
Assert(IsA(linitial(rel->partial_pathlist),CustomPath));
283+
list_free(parallel_safe_lst);
266284
}
267285

268286
void
@@ -287,3 +305,21 @@ _PG_init(void)
287305

288306
MarkGUCPrefixReserved(MODULENAME);
289307
}
308+
309+
/* *****************************************************************************
310+
*
311+
* Parallel transport stuff
312+
*
313+
**************************************************************************** */
314+
315+
/* copy from execParallel.c */
316+
#definePARALLEL_TUPLE_QUEUE_SIZE65536
317+
318+
staticSize
319+
EstimateDSMTempScan(CustomScanState*node,ParallelContext*pcxt)
320+
{
321+
Sizesize;
322+
323+
size=mul_size(PARALLEL_TUPLE_QUEUE_SIZE,pcxt->nworkers);
324+
returnsize;
325+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp