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

Commit36d22dd

Browse files
committed
Don't generate EEOP_*_FETCHSOME operations for slots know to be virtual.
That avoids unnecessary work during both interpreted execution, andJIT compiled expression evaluation. Both benefit from fewer expressionsteps needing be processed, and for interpreted execution there now isa fastpath dedicated to just fetching a value from a virtualslot. That's e.g. beneficial for hashjoins over nodes that performprojections, as the hashed columns are currently fetched individually.Author: Soumyadeep Chakraborty, Andres FreundDiscussion:https://postgr.es/m/CAE-ML+9OKSN71+mHtfMD-L24oDp8dGTfaVjDU6U+j+FNAW5kRQ@mail.gmail.com
1 parent34c9c53 commit36d22dd

File tree

3 files changed

+160
-22
lines changed

3 files changed

+160
-22
lines changed

‎src/backend/executor/execExpr.c

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args,
6565
staticvoidExecInitExprSlots(ExprState*state,Node*node);
6666
staticvoidExecPushExprSlots(ExprState*state,LastAttnumInfo*info);
6767
staticboolget_last_attnums_walker(Node*node,LastAttnumInfo*info);
68-
staticvoidExecComputeSlotInfo(ExprState*state,ExprEvalStep*op);
68+
staticboolExecComputeSlotInfo(ExprState*state,ExprEvalStep*op);
6969
staticvoidExecInitWholeRowVar(ExprEvalStep*scratch,Var*variable,
7070
ExprState*state);
7171
staticvoidExecInitSubscriptingRef(ExprEvalStep*scratch,
@@ -2285,8 +2285,8 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
22852285
scratch.d.fetch.fixed= false;
22862286
scratch.d.fetch.kind=NULL;
22872287
scratch.d.fetch.known_desc=NULL;
2288-
ExecComputeSlotInfo(state,&scratch);
2289-
ExprEvalPushStep(state,&scratch);
2288+
if (ExecComputeSlotInfo(state,&scratch))
2289+
ExprEvalPushStep(state,&scratch);
22902290
}
22912291
if (info->last_outer>0)
22922292
{
@@ -2295,8 +2295,8 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
22952295
scratch.d.fetch.fixed= false;
22962296
scratch.d.fetch.kind=NULL;
22972297
scratch.d.fetch.known_desc=NULL;
2298-
ExecComputeSlotInfo(state,&scratch);
2299-
ExprEvalPushStep(state,&scratch);
2298+
if (ExecComputeSlotInfo(state,&scratch))
2299+
ExprEvalPushStep(state,&scratch);
23002300
}
23012301
if (info->last_scan>0)
23022302
{
@@ -2305,8 +2305,8 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
23052305
scratch.d.fetch.fixed= false;
23062306
scratch.d.fetch.kind=NULL;
23072307
scratch.d.fetch.known_desc=NULL;
2308-
ExecComputeSlotInfo(state,&scratch);
2309-
ExprEvalPushStep(state,&scratch);
2308+
if (ExecComputeSlotInfo(state,&scratch))
2309+
ExprEvalPushStep(state,&scratch);
23102310
}
23112311
}
23122312

@@ -2364,14 +2364,21 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
23642364
* The goal is to determine whether a slot is 'fixed', that is, every
23652365
* evaluation of the expression will have the same type of slot, with an
23662366
* equivalent descriptor.
2367+
*
2368+
* Returns true if the the deforming step is required, false otherwise.
23672369
*/
2368-
staticvoid
2370+
staticbool
23692371
ExecComputeSlotInfo(ExprState*state,ExprEvalStep*op)
23702372
{
23712373
PlanState*parent=state->parent;
23722374
TupleDescdesc=NULL;
23732375
constTupleTableSlotOps*tts_ops=NULL;
23742376
boolisfixed= false;
2377+
ExprEvalOpopcode=op->opcode;
2378+
2379+
Assert(opcode==EEOP_INNER_FETCHSOME||
2380+
opcode==EEOP_OUTER_FETCHSOME||
2381+
opcode==EEOP_SCAN_FETCHSOME);
23752382

23762383
if (op->d.fetch.known_desc!=NULL)
23772384
{
@@ -2383,7 +2390,7 @@ ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
23832390
{
23842391
isfixed= false;
23852392
}
2386-
elseif (op->opcode==EEOP_INNER_FETCHSOME)
2393+
elseif (opcode==EEOP_INNER_FETCHSOME)
23872394
{
23882395
PlanState*is=innerPlanState(parent);
23892396

@@ -2403,7 +2410,7 @@ ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
24032410
desc=ExecGetResultType(is);
24042411
}
24052412
}
2406-
elseif (op->opcode==EEOP_OUTER_FETCHSOME)
2413+
elseif (opcode==EEOP_OUTER_FETCHSOME)
24072414
{
24082415
PlanState*os=outerPlanState(parent);
24092416

@@ -2423,7 +2430,7 @@ ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
24232430
desc=ExecGetResultType(os);
24242431
}
24252432
}
2426-
elseif (op->opcode==EEOP_SCAN_FETCHSOME)
2433+
elseif (opcode==EEOP_SCAN_FETCHSOME)
24272434
{
24282435
desc=parent->scandesc;
24292436

@@ -2446,6 +2453,12 @@ ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
24462453
op->d.fetch.kind=NULL;
24472454
op->d.fetch.known_desc=NULL;
24482455
}
2456+
2457+
/* if the slot is known to always virtual we never need to deform */
2458+
if (op->d.fetch.fixed&&op->d.fetch.kind==&TTSOpsVirtual)
2459+
return false;
2460+
2461+
return true;
24492462
}
24502463

24512464
/*
@@ -3360,16 +3373,16 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
33603373
scratch.d.fetch.fixed= false;
33613374
scratch.d.fetch.known_desc=ldesc;
33623375
scratch.d.fetch.kind=lops;
3363-
ExecComputeSlotInfo(state,&scratch);
3364-
ExprEvalPushStep(state,&scratch);
3376+
if (ExecComputeSlotInfo(state,&scratch))
3377+
ExprEvalPushStep(state,&scratch);
33653378

33663379
scratch.opcode=EEOP_OUTER_FETCHSOME;
33673380
scratch.d.fetch.last_var=maxatt;
33683381
scratch.d.fetch.fixed= false;
33693382
scratch.d.fetch.known_desc=rdesc;
33703383
scratch.d.fetch.kind=rops;
3371-
ExecComputeSlotInfo(state,&scratch);
3372-
ExprEvalPushStep(state,&scratch);
3384+
if (ExecComputeSlotInfo(state,&scratch))
3385+
ExprEvalPushStep(state,&scratch);
33733386

33743387
/*
33753388
* Start comparing at the last field (least significant sort key). That's

‎src/backend/executor/execExprInterp.c

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, boo
160160
staticDatumExecJustAssignScanVar(ExprState*state,ExprContext*econtext,bool*isnull);
161161
staticDatumExecJustApplyFuncToCase(ExprState*state,ExprContext*econtext,bool*isnull);
162162
staticDatumExecJustConst(ExprState*state,ExprContext*econtext,bool*isnull);
163+
staticDatumExecJustInnerVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
164+
staticDatumExecJustOuterVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
165+
staticDatumExecJustScanVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
166+
staticDatumExecJustAssignInnerVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
167+
staticDatumExecJustAssignOuterVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
168+
staticDatumExecJustAssignScanVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
163169

164170

165171
/*
@@ -255,11 +261,45 @@ ExecReadyInterpretedExpr(ExprState *state)
255261
return;
256262
}
257263
}
258-
elseif (state->steps_len==2&&
259-
state->steps[0].opcode==EEOP_CONST)
264+
elseif (state->steps_len==2)
260265
{
261-
state->evalfunc_private= (void*)ExecJustConst;
262-
return;
266+
ExprEvalOpstep0=state->steps[0].opcode;
267+
268+
if (step0==EEOP_CONST)
269+
{
270+
state->evalfunc_private= (void*)ExecJustConst;
271+
return;
272+
}
273+
elseif (step0==EEOP_INNER_VAR)
274+
{
275+
state->evalfunc_private= (void*)ExecJustInnerVarVirt;
276+
return;
277+
}
278+
elseif (step0==EEOP_OUTER_VAR)
279+
{
280+
state->evalfunc_private= (void*)ExecJustOuterVarVirt;
281+
return;
282+
}
283+
elseif (step0==EEOP_SCAN_VAR)
284+
{
285+
state->evalfunc_private= (void*)ExecJustScanVarVirt;
286+
return;
287+
}
288+
elseif (step0==EEOP_ASSIGN_INNER_VAR)
289+
{
290+
state->evalfunc_private= (void*)ExecJustAssignInnerVarVirt;
291+
return;
292+
}
293+
elseif (step0==EEOP_ASSIGN_OUTER_VAR)
294+
{
295+
state->evalfunc_private= (void*)ExecJustAssignOuterVarVirt;
296+
return;
297+
}
298+
elseif (step0==EEOP_ASSIGN_SCAN_VAR)
299+
{
300+
state->evalfunc_private= (void*)ExecJustAssignScanVarVirt;
301+
return;
302+
}
263303
}
264304

265305
#if defined(EEO_USE_COMPUTED_GOTO)
@@ -2096,6 +2136,91 @@ ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
20962136
returnop->d.constval.value;
20972137
}
20982138

2139+
/* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
2140+
staticpg_attribute_always_inlineDatum
2141+
ExecJustVarVirtImpl(ExprState*state,TupleTableSlot*slot,bool*isnull)
2142+
{
2143+
ExprEvalStep*op=&state->steps[0];
2144+
intattnum=op->d.var.attnum;
2145+
2146+
/*
2147+
* As it is guaranteed that a virtual slot is used, there never is a need
2148+
* to perform tuple deforming (nor would it be possible). Therefore
2149+
* execExpr.c has not emitted an EEOP_*_FETCHSOME step. Verify, as much as
2150+
* possible, that that determination was accurate.
2151+
*/
2152+
Assert(TTS_IS_VIRTUAL(slot));
2153+
Assert(TTS_FIXED(slot));
2154+
Assert(attnum >=0&&attnum<slot->tts_nvalid);
2155+
2156+
*isnull=slot->tts_isnull[attnum];
2157+
2158+
returnslot->tts_values[attnum];
2159+
}
2160+
2161+
/* Like ExecJustInnerVar, optimized for virtual slots */
2162+
staticDatum
2163+
ExecJustInnerVarVirt(ExprState*state,ExprContext*econtext,bool*isnull)
2164+
{
2165+
returnExecJustVarVirtImpl(state,econtext->ecxt_innertuple,isnull);
2166+
}
2167+
2168+
/* Like ExecJustOuterVar, optimized for virtual slots */
2169+
staticDatum
2170+
ExecJustOuterVarVirt(ExprState*state,ExprContext*econtext,bool*isnull)
2171+
{
2172+
returnExecJustVarVirtImpl(state,econtext->ecxt_outertuple,isnull);
2173+
}
2174+
2175+
/* Like ExecJustScanVar, optimized for virtual slots */
2176+
staticDatum
2177+
ExecJustScanVarVirt(ExprState*state,ExprContext*econtext,bool*isnull)
2178+
{
2179+
returnExecJustVarVirtImpl(state,econtext->ecxt_scantuple,isnull);
2180+
}
2181+
2182+
/* implementation of ExecJustAssign(Inner|Outer|Scan)VarVirt */
2183+
staticpg_attribute_always_inlineDatum
2184+
ExecJustAssignVarVirtImpl(ExprState*state,TupleTableSlot*inslot,bool*isnull)
2185+
{
2186+
ExprEvalStep*op=&state->steps[0];
2187+
intattnum=op->d.assign_var.attnum;
2188+
intresultnum=op->d.assign_var.resultnum;
2189+
TupleTableSlot*outslot=state->resultslot;
2190+
2191+
/* see ExecJustVarVirtImpl for comments */
2192+
2193+
Assert(TTS_IS_VIRTUAL(inslot));
2194+
Assert(TTS_FIXED(inslot));
2195+
Assert(attnum >=0&&attnum<inslot->tts_nvalid);
2196+
2197+
outslot->tts_values[resultnum]=inslot->tts_values[attnum];
2198+
outslot->tts_isnull[resultnum]=inslot->tts_isnull[attnum];
2199+
2200+
return0;
2201+
}
2202+
2203+
/* Like ExecJustAssignInnerVar, optimized for virtual slots */
2204+
staticDatum
2205+
ExecJustAssignInnerVarVirt(ExprState*state,ExprContext*econtext,bool*isnull)
2206+
{
2207+
returnExecJustAssignVarVirtImpl(state,econtext->ecxt_innertuple,isnull);
2208+
}
2209+
2210+
/* Like ExecJustAssignOuterVar, optimized for virtual slots */
2211+
staticDatum
2212+
ExecJustAssignOuterVarVirt(ExprState*state,ExprContext*econtext,bool*isnull)
2213+
{
2214+
returnExecJustAssignVarVirtImpl(state,econtext->ecxt_outertuple,isnull);
2215+
}
2216+
2217+
/* Like ExecJustAssignScanVar, optimized for virtual slots */
2218+
staticDatum
2219+
ExecJustAssignScanVarVirt(ExprState*state,ExprContext*econtext,bool*isnull)
2220+
{
2221+
returnExecJustAssignVarVirtImpl(state,econtext->ecxt_scantuple,isnull);
2222+
}
2223+
20992224
#if defined(EEO_USE_COMPUTED_GOTO)
21002225
/*
21012226
* Comparator used when building address->opcode lookup table for

‎src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ llvm_compile_expr(ExprState *state)
287287
if (op->d.fetch.fixed)
288288
tts_ops=op->d.fetch.kind;
289289

290+
/* step should not have been generated */
291+
Assert(tts_ops!=&TTSOpsVirtual);
292+
290293
if (opcode==EEOP_INNER_FETCHSOME)
291294
v_slot=v_innerslot;
292295
elseif (opcode==EEOP_OUTER_FETCHSOME)
@@ -297,9 +300,6 @@ llvm_compile_expr(ExprState *state)
297300
/*
298301
* Check if all required attributes are available, or
299302
* whether deforming is required.
300-
*
301-
* TODO: skip nvalid check if slot is fixed and known to
302-
* be a virtual slot.
303303
*/
304304
v_nvalid=
305305
l_load_struct_gep(b,v_slot,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp