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

Commit11be868

Browse files
committed
Initial commit
This commit can show EXPLAIN of partial plans including temporary tables.Just for demo. Don't even try to execute that!
1 parent82ed67a commit11be868

File tree

6 files changed

+370
-0
lines changed

6 files changed

+370
-0
lines changed

‎contrib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ SUBDIRS = \
4545
spi\
4646
tablefunc\
4747
tcn\
48+
tempscan\
4849
test_decoding\
4950
tsm_system_rows\
5051
tsm_system_time\

‎contrib/tempscan/Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# contrib/tempscan/Makefile
2+
3+
MODULE_big = tempscan
4+
OBJS =\
5+
$(WIN32RES)\
6+
nodeCustomTempScan.o\
7+
8+
EXTENSION = tempscan
9+
PGFILEDESC = "tempscan - Parallel Scan of Temporary Table"
10+
11+
REGRESS = basic
12+
13+
ifdefUSE_PGXS
14+
PG_CONFIG = pg_config
15+
PGXS :=$(shell$(PG_CONFIG) --pgxs)
16+
include$(PGXS)
17+
else
18+
subdir = contrib/tempscan
19+
top_builddir = ../..
20+
include$(top_builddir)/src/Makefile.global
21+
include$(top_srcdir)/contrib/contrib-global.mk
22+
endif

‎contrib/tempscan/expected/basic.out

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--
2+
-- Copyright (c) 2017-2024, Postgres Professional
3+
--
4+
-- Set of basic regression tests on scanning of a temporary table in parallel
5+
--
6+
-- Load the library. It should be load dynamically
7+
LOAD 'tempscan';
8+
-- Force usage of parallel workers
9+
SET max_parallel_workers_per_gather = 3;
10+
SET parallel_setup_cost = 0.0001;
11+
SET parallel_tuple_cost = 0.0001;
12+
-- Don't need big tables
13+
SET min_parallel_table_scan_size = 0;
14+
SET min_parallel_index_scan_size = 0;
15+
CREATE TABLE parallel_test (x int);
16+
INSERT INTO parallel_test (x) SELECT x FROM generate_series(1,100) AS x;
17+
CREATE TEMP TABLE parallel_test_tmp AS (SELECT * FROM parallel_test);
18+
VACUUM ANALYZE parallel_test, parallel_test_tmp;
19+
SET tempscan.enable = 'on';
20+
EXPLAIN (COSTS OFF)
21+
SELECT count(*) FROM parallel_test;
22+
QUERY PLAN
23+
------------------------------------------------------
24+
Finalize Aggregate
25+
-> Gather
26+
Workers Planned: 1
27+
-> Partial Aggregate
28+
-> Parallel Seq Scan on parallel_test
29+
(5 rows)
30+
31+
-- Should also utilise parallel workers like scanning of a plain table
32+
EXPLAIN (COSTS OFF)
33+
SELECT count(*) FROM parallel_test_tmp;
34+
QUERY PLAN
35+
----------------------------------------------------------
36+
Aggregate
37+
-> Gather
38+
Workers Planned: 1
39+
-> Custom Scan (nodeCustomTempScan)
40+
-> Parallel Seq Scan on parallel_test_tmp
41+
(5 rows)
42+
43+
RESET tempscan.enable;
44+
DROP TABLE parallel_test, parallel_test_tmp;

‎contrib/tempscan/nodeCustomTempScan.c

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
/* -------------------------------------------------------------------------
2+
*
3+
* nodeCustomTempScan.c
4+
*Implements strategy which allows to build and execute partial paths for
5+
*a query which contains tempoorary table scans.
6+
*
7+
* Copyright (c) 2017-2024, Postgres Professional
8+
*
9+
* IDENTIFICATION
10+
*contrib/tempscan/nodeCustomTempScan.c
11+
*
12+
* -------------------------------------------------------------------------
13+
*/
14+
#include"postgres.h"
15+
16+
#include"nodes/extensible.h"
17+
#include"optimizer/cost.h"
18+
#include"optimizer/pathnode.h"
19+
#include"optimizer/paths.h"
20+
#include"utils/guc.h"
21+
#include"utils/lsyscache.h"
22+
#include"utils/rel.h"
23+
24+
PG_MODULE_MAGIC;
25+
26+
#defineMODULENAME"tempscan"
27+
#defineNODENAME"nodeCustomTempScan"
28+
29+
staticPlan*create_partial_tempscan_plan(PlannerInfo*root,
30+
RelOptInfo*rel,
31+
CustomPath*best_path,
32+
List*tlist,
33+
List*scan_clauses,
34+
List*custom_plans);
35+
staticNode*create_tempscan_state(CustomScan*cscan);
36+
staticvoidBeginTempScan(CustomScanState*node,EState*estate,inteflags);
37+
staticTupleTableSlot*ExecTempScan(CustomScanState*node);
38+
staticvoidEndTempScan(CustomScanState*node);
39+
staticvoidReScanTempScan(CustomScanState*node);
40+
41+
staticCustomPathMethodspath_methods=
42+
{
43+
.CustomName=NODENAME,
44+
.PlanCustomPath=create_partial_tempscan_plan,
45+
.ReparameterizeCustomPathByChild=NULL
46+
};
47+
48+
staticCustomScanMethodsplan_methods=
49+
{
50+
.CustomName=NODENAME,
51+
.CreateCustomScanState=create_tempscan_state
52+
};
53+
54+
staticCustomExecMethodsexec_methods=
55+
{
56+
.CustomName=NODENAME,
57+
58+
.BeginCustomScan=BeginTempScan,
59+
.ExecCustomScan=ExecTempScan,
60+
.EndCustomScan=EndTempScan,
61+
.ReScanCustomScan=ReScanTempScan,
62+
.MarkPosCustomScan=NULL,
63+
.RestrPosCustomScan=NULL,
64+
.EstimateDSMCustomScan=NULL,
65+
.InitializeDSMCustomScan=NULL,
66+
.ReInitializeDSMCustomScan=NULL,
67+
.InitializeWorkerCustomScan=NULL,
68+
.ShutdownCustomScan=NULL,
69+
.ExplainCustomScan=NULL
70+
};
71+
72+
staticset_rel_pathlist_hook_typeset_rel_pathlist_hook_next=NULL;
73+
staticbooltempscan_enable= false;
74+
75+
void_PG_init(void);
76+
77+
/*
78+
* The input path shouldn't be a part of the relation pathlist.
79+
*/
80+
staticCustomPath*
81+
create_partial_tempscan_path(PlannerInfo*root,RelOptInfo*rel,
82+
Path*path)
83+
{
84+
CustomPath*cpath;
85+
Path*pathnode;
86+
87+
cpath=makeNode(CustomPath);
88+
pathnode=&cpath->path;
89+
90+
pathnode->pathtype=T_CustomScan;
91+
pathnode->parent=rel;
92+
pathnode->pathtarget=rel->reltarget;
93+
pathnode->rows=rel->rows;
94+
95+
/* XXX: Just for now */
96+
pathnode->param_info=NULL;
97+
98+
pathnode->parallel_safe= true;
99+
pathnode->parallel_aware= false;
100+
pathnode->parallel_workers=path->parallel_workers;
101+
102+
/* DEBUGGING purposes only */
103+
pathnode->startup_cost=path->startup_cost /disable_cost;
104+
pathnode->total_cost=path->total_cost /disable_cost;
105+
106+
cpath->custom_paths=list_make1(path);
107+
cpath->custom_private=NIL;
108+
cpath->custom_restrictinfo=NIL;
109+
cpath->methods=&path_methods;
110+
111+
returncpath;
112+
}
113+
114+
staticPlan*
115+
create_partial_tempscan_plan(PlannerInfo*root,RelOptInfo*rel,
116+
CustomPath*best_path,List*tlist,
117+
List*scan_clauses,List*custom_plans)
118+
{
119+
CustomScan*cscan=makeNode(CustomScan);
120+
121+
Assert(list_length(custom_plans)==1);
122+
Assert(best_path->path.parallel_safe= true&&
123+
best_path->path.parallel_workers>0);
124+
125+
126+
cscan->scan.plan.targetlist=cscan->custom_scan_tlist=tlist;
127+
cscan->scan.scanrelid=0;
128+
cscan->custom_exprs=NIL;
129+
cscan->custom_plans=custom_plans;
130+
cscan->methods=&plan_methods;
131+
cscan->flags=best_path->flags;
132+
cscan->custom_private=best_path->custom_private;
133+
134+
return&cscan->scan.plan;
135+
}
136+
137+
staticNode*
138+
create_tempscan_state(CustomScan*cscan)
139+
{
140+
CustomScanState*cstate=makeNode(CustomScanState);
141+
142+
cstate->methods=&exec_methods;
143+
144+
return (Node*)cstate;
145+
}
146+
147+
staticvoid
148+
BeginTempScan(CustomScanState*node,EState*estate,inteflags)
149+
{
150+
CustomScan*cscan= (CustomScan*)node->ss.ps.plan;
151+
Plan*subplan;
152+
PlanState*pstate;
153+
154+
Assert(list_length(cscan->custom_plans)==1);
155+
156+
subplan= (Plan*)linitial(cscan->custom_plans);
157+
pstate=ExecInitNode(subplan,estate,eflags);
158+
node->custom_ps=lappend(node->custom_ps, (void*)pstate);
159+
}
160+
161+
staticTupleTableSlot*
162+
ExecTempScan(CustomScanState*node)
163+
{
164+
Assert(list_length(node->custom_ps)==1);
165+
166+
returnExecProcNode((PlanState*)linitial(node->custom_ps));
167+
}
168+
169+
staticvoid
170+
EndTempScan(CustomScanState*node)
171+
{
172+
ExecClearTuple(node->ss.ss_ScanTupleSlot);
173+
ExecEndNode((PlanState*)linitial(node->custom_ps));
174+
}
175+
176+
staticvoid
177+
ReScanTempScan(CustomScanState*node)
178+
{
179+
PlanState*child;
180+
181+
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
182+
183+
child= (PlanState*)linitial(node->custom_ps);
184+
185+
if (node->ss.ps.chgParam!=NULL)
186+
UpdateChangedParamSet(child,node->ss.ps.chgParam);
187+
188+
ExecReScan(child);
189+
}
190+
191+
/*
192+
* Try to add partial paths to the scan of a temporary table.
193+
*
194+
* In contrast to the hook on a JOIN paths creation, here we already at the end
195+
* of paths creation procedure, right before insertion of a gather node.
196+
* So, we can discover pathlist and choose any base path we can and want to use
197+
* in parallel scan.
198+
*
199+
* TODO: add inner strategy for temp table scan (parallel_workers == 0,
200+
* parallel_safe == true). Right now it looks a bit more difficult to implement.
201+
*/
202+
staticvoid
203+
try_partial_tempscan(PlannerInfo*root,RelOptInfo*rel,Indexrti,
204+
RangeTblEntry*rte)
205+
{
206+
intparallel_workers;
207+
Path*path;
208+
209+
/*
210+
* Some extension intercept this hook earlier. Allow it to do a work
211+
* before us.
212+
*/
213+
if (set_rel_pathlist_hook_next)
214+
(*set_rel_pathlist_hook_next)(root,rel,rti,rte);
215+
216+
if (rel->consider_parallel)
217+
return;
218+
219+
if (rte->rtekind!=RTE_RELATION||
220+
get_rel_persistence(rte->relid)!=RELPERSISTENCE_TEMP)
221+
return;
222+
223+
parallel_workers=compute_parallel_worker(rel,rel->pages,-1,
224+
max_parallel_workers_per_gather);
225+
226+
/* If any limit was set to zero, the user doesn't want a parallel scan. */
227+
if (parallel_workers <=0)
228+
return;
229+
230+
/* HACK */
231+
rel->consider_parallel= true;
232+
233+
path=create_seqscan_path(root,rel,NULL,parallel_workers);
234+
if (path)
235+
{
236+
/* Add an unordered partial path based on a parallel sequential scan. */
237+
add_partial_path(rel, (Path*)
238+
create_partial_tempscan_path(root,rel,path));
239+
}
240+
241+
if (!bms_equal(rel->relids,root->all_query_rels))
242+
rel->consider_parallel= false;
243+
Assert(IsA(linitial(rel->partial_pathlist),CustomPath));
244+
}
245+
246+
void
247+
_PG_init(void)
248+
{
249+
DefineCustomBoolVariable("tempscan.enable",
250+
"Enable feature of the parallel temporary table scan.",
251+
"Right now no any other purpose except debugging",
252+
&tempscan_enable,
253+
false,
254+
PGC_SUSET,
255+
0,
256+
NULL,
257+
NULL,
258+
NULL
259+
);
260+
261+
set_rel_pathlist_hook_next=set_rel_pathlist_hook;
262+
set_rel_pathlist_hook=try_partial_tempscan;
263+
264+
MarkGUCPrefixReserved(MODULENAME);
265+
}

‎contrib/tempscan/sql/basic.sql

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--
2+
-- Copyright (c) 2017-2024, Postgres Professional
3+
--
4+
-- Set of basic regression tests on scanning of a temporary table in parallel
5+
--
6+
7+
-- Load the library. It should be load dynamically
8+
LOAD'tempscan';
9+
10+
-- Force usage of parallel workers
11+
SET max_parallel_workers_per_gather=3;
12+
SET parallel_setup_cost=0.0001;
13+
SET parallel_tuple_cost=0.0001;
14+
15+
-- Don't need big tables
16+
SET min_parallel_table_scan_size=0;
17+
SET min_parallel_index_scan_size=0;
18+
19+
CREATETABLEparallel_test (xint);
20+
INSERT INTO parallel_test (x)SELECT xFROM generate_series(1,100)AS x;
21+
CREATE TEMP TABLE parallel_test_tmpAS (SELECT*FROM parallel_test);
22+
VACUUM ANALYZE parallel_test, parallel_test_tmp;
23+
24+
SETtempscan.enable='on';
25+
EXPLAIN (COSTS OFF)
26+
SELECTcount(*)FROM parallel_test;
27+
28+
-- Should also utilise parallel workers like scanning of a plain table
29+
EXPLAIN (COSTS OFF)
30+
SELECTcount(*)FROM parallel_test_tmp;
31+
32+
RESETtempscan.enable;
33+
DROPTABLE parallel_test, parallel_test_tmp;

‎contrib/tempscan/tempscan.control

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# tempscan
2+
comment = 'Parallel Temp Table Scan'
3+
default_version = '0.1'
4+
module_pathname = '$libdir/tempscan'
5+
relocatable = true

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp