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

Commit50416cc

Browse files
committed
Speedup Hash Joins with dedicated functions for ExprState hashing
Hashing of a single Var is a very common operation for ExprState toperform. Here we add dedicated ExecJust* functions which helps speed upHash Joins by removing the interpretation overhead in ExecInterpExpr().This change currently only affects Hash Joins on a single column. HashJoins with multiple join keys or an expression still run throughExecInterpExpr().Some testing has shown up to 10% query performance increases on recent AMDhardware and nearly 7% increase on an Apple M2 for a query performing ahash join with a large number of lookups on a small hash table.This change was extracted from a larger patch which adjusts GROUP BY /hashed subplans / hashed set operations to use ExprState hashing.Discussion:https://postgr.es/m/CAApHDvr8Zc0ZgzVoCZLdHGOFNhiJeQ6vrUcS9V7N23zMWQb-eA@mail.gmail.com
1 parent9828905 commit50416cc

File tree

1 file changed

+205
-1
lines changed

1 file changed

+205
-1
lines changed

‎src/backend/executor/execExprInterp.c‎

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *
168168
staticDatumExecJustAssignInnerVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
169169
staticDatumExecJustAssignOuterVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
170170
staticDatumExecJustAssignScanVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
171+
staticDatumExecJustHashInnerVarWithIV(ExprState*state,ExprContext*econtext,bool*isnull);
172+
staticDatumExecJustHashOuterVar(ExprState*state,ExprContext*econtext,bool*isnull);
173+
staticDatumExecJustHashInnerVar(ExprState*state,ExprContext*econtext,bool*isnull);
174+
staticDatumExecJustHashOuterVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
175+
staticDatumExecJustHashInnerVarVirt(ExprState*state,ExprContext*econtext,bool*isnull);
176+
staticDatumExecJustHashOuterVarStrict(ExprState*state,ExprContext*econtext,bool*isnull);
171177

172178
/* execution helper functions */
173179
staticpg_attribute_always_inlinevoidExecAggPlainTransByVal(AggState*aggstate,
@@ -273,7 +279,51 @@ ExecReadyInterpretedExpr(ExprState *state)
273279
* the full interpreter is a measurable overhead for these, and these
274280
* patterns occur often enough to be worth optimizing.
275281
*/
276-
if (state->steps_len==3)
282+
if (state->steps_len==5)
283+
{
284+
ExprEvalOpstep0=state->steps[0].opcode;
285+
ExprEvalOpstep1=state->steps[1].opcode;
286+
ExprEvalOpstep2=state->steps[2].opcode;
287+
ExprEvalOpstep3=state->steps[3].opcode;
288+
289+
if (step0==EEOP_INNER_FETCHSOME&&
290+
step1==EEOP_HASHDATUM_SET_INITVAL&&
291+
step2==EEOP_INNER_VAR&&
292+
step3==EEOP_HASHDATUM_NEXT32)
293+
{
294+
state->evalfunc_private= (void*)ExecJustHashInnerVarWithIV;
295+
return;
296+
}
297+
}
298+
elseif (state->steps_len==4)
299+
{
300+
ExprEvalOpstep0=state->steps[0].opcode;
301+
ExprEvalOpstep1=state->steps[1].opcode;
302+
ExprEvalOpstep2=state->steps[2].opcode;
303+
304+
if (step0==EEOP_OUTER_FETCHSOME&&
305+
step1==EEOP_OUTER_VAR&&
306+
step2==EEOP_HASHDATUM_FIRST)
307+
{
308+
state->evalfunc_private= (void*)ExecJustHashOuterVar;
309+
return;
310+
}
311+
elseif (step0==EEOP_INNER_FETCHSOME&&
312+
step1==EEOP_INNER_VAR&&
313+
step2==EEOP_HASHDATUM_FIRST)
314+
{
315+
state->evalfunc_private= (void*)ExecJustHashInnerVar;
316+
return;
317+
}
318+
elseif (step0==EEOP_OUTER_FETCHSOME&&
319+
step1==EEOP_OUTER_VAR&&
320+
step2==EEOP_HASHDATUM_FIRST_STRICT)
321+
{
322+
state->evalfunc_private= (void*)ExecJustHashOuterVarStrict;
323+
return;
324+
}
325+
}
326+
elseif (state->steps_len==3)
277327
{
278328
ExprEvalOpstep0=state->steps[0].opcode;
279329
ExprEvalOpstep1=state->steps[1].opcode;
@@ -321,6 +371,18 @@ ExecReadyInterpretedExpr(ExprState *state)
321371
state->evalfunc_private=ExecJustApplyFuncToCase;
322372
return;
323373
}
374+
elseif (step0==EEOP_INNER_VAR&&
375+
step1==EEOP_HASHDATUM_FIRST)
376+
{
377+
state->evalfunc_private= (void*)ExecJustHashInnerVarVirt;
378+
return;
379+
}
380+
elseif (step0==EEOP_OUTER_VAR&&
381+
step1==EEOP_HASHDATUM_FIRST)
382+
{
383+
state->evalfunc_private= (void*)ExecJustHashOuterVarVirt;
384+
return;
385+
}
324386
}
325387
elseif (state->steps_len==2)
326388
{
@@ -2484,6 +2546,148 @@ ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
24842546
returnExecJustAssignVarVirtImpl(state,econtext->ecxt_scantuple,isnull);
24852547
}
24862548

2549+
/*
2550+
* implementation for hashing an inner Var, seeding with an initial value.
2551+
*/
2552+
staticDatum
2553+
ExecJustHashInnerVarWithIV(ExprState*state,ExprContext*econtext,
2554+
bool*isnull)
2555+
{
2556+
ExprEvalStep*fetchop=&state->steps[0];
2557+
ExprEvalStep*setivop=&state->steps[1];
2558+
ExprEvalStep*innervar=&state->steps[2];
2559+
ExprEvalStep*hashop=&state->steps[3];
2560+
FunctionCallInfofcinfo=hashop->d.hashdatum.fcinfo_data;
2561+
intattnum=innervar->d.var.attnum;
2562+
uint32hashkey;
2563+
2564+
CheckOpSlotCompatibility(fetchop,econtext->ecxt_innertuple);
2565+
slot_getsomeattrs(econtext->ecxt_innertuple,fetchop->d.fetch.last_var);
2566+
2567+
fcinfo->args[0].value=econtext->ecxt_innertuple->tts_values[attnum];
2568+
fcinfo->args[0].isnull=econtext->ecxt_innertuple->tts_isnull[attnum];
2569+
2570+
hashkey=DatumGetUInt32(setivop->d.hashdatum_initvalue.init_value);
2571+
hashkey=pg_rotate_left32(hashkey,1);
2572+
2573+
if (!fcinfo->args[0].isnull)
2574+
{
2575+
uint32hashvalue;
2576+
2577+
hashvalue=DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2578+
hashkey=hashkey ^hashvalue;
2579+
}
2580+
2581+
*isnull= false;
2582+
returnUInt32GetDatum(hashkey);
2583+
}
2584+
2585+
/* implementation of ExecJustHash(Inner|Outer)Var */
2586+
staticpg_attribute_always_inlineDatum
2587+
ExecJustHashVarImpl(ExprState*state,TupleTableSlot*slot,bool*isnull)
2588+
{
2589+
ExprEvalStep*fetchop=&state->steps[0];
2590+
ExprEvalStep*var=&state->steps[1];
2591+
ExprEvalStep*hashop=&state->steps[2];
2592+
FunctionCallInfofcinfo=hashop->d.hashdatum.fcinfo_data;
2593+
intattnum=var->d.var.attnum;
2594+
2595+
CheckOpSlotCompatibility(fetchop,slot);
2596+
slot_getsomeattrs(slot,fetchop->d.fetch.last_var);
2597+
2598+
fcinfo->args[0].value=slot->tts_values[attnum];
2599+
fcinfo->args[0].isnull=slot->tts_isnull[attnum];
2600+
2601+
*isnull= false;
2602+
2603+
if (!fcinfo->args[0].isnull)
2604+
returnDatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2605+
else
2606+
return (Datum)0;
2607+
}
2608+
2609+
/* implementation for hashing an outer Var */
2610+
staticDatum
2611+
ExecJustHashOuterVar(ExprState*state,ExprContext*econtext,bool*isnull)
2612+
{
2613+
returnExecJustHashVarImpl(state,econtext->ecxt_outertuple,isnull);
2614+
}
2615+
2616+
/* implementation for hashing an inner Var */
2617+
staticDatum
2618+
ExecJustHashInnerVar(ExprState*state,ExprContext*econtext,bool*isnull)
2619+
{
2620+
returnExecJustHashVarImpl(state,econtext->ecxt_innertuple,isnull);
2621+
}
2622+
2623+
/* implementation of ExecJustHash(Inner|Outer)VarVirt */
2624+
staticpg_attribute_always_inlineDatum
2625+
ExecJustHashVarVirtImpl(ExprState*state,TupleTableSlot*slot,bool*isnull)
2626+
{
2627+
ExprEvalStep*var=&state->steps[0];
2628+
ExprEvalStep*hashop=&state->steps[1];
2629+
FunctionCallInfofcinfo=hashop->d.hashdatum.fcinfo_data;
2630+
intattnum=var->d.var.attnum;
2631+
2632+
fcinfo->args[0].value=slot->tts_values[attnum];
2633+
fcinfo->args[0].isnull=slot->tts_isnull[attnum];
2634+
2635+
*isnull= false;
2636+
2637+
if (!fcinfo->args[0].isnull)
2638+
returnDatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2639+
else
2640+
return (Datum)0;
2641+
}
2642+
2643+
/* Like ExecJustHashInnerVar, optimized for virtual slots */
2644+
staticDatum
2645+
ExecJustHashInnerVarVirt(ExprState*state,ExprContext*econtext,
2646+
bool*isnull)
2647+
{
2648+
returnExecJustHashVarVirtImpl(state,econtext->ecxt_innertuple,isnull);
2649+
}
2650+
2651+
/* Like ExecJustHashOuterVar, optimized for virtual slots */
2652+
staticDatum
2653+
ExecJustHashOuterVarVirt(ExprState*state,ExprContext*econtext,
2654+
bool*isnull)
2655+
{
2656+
returnExecJustHashVarVirtImpl(state,econtext->ecxt_outertuple,isnull);
2657+
}
2658+
2659+
/*
2660+
* implementation for hashing an outer Var. Returns NULL on NULL input.
2661+
*/
2662+
staticDatum
2663+
ExecJustHashOuterVarStrict(ExprState*state,ExprContext*econtext,
2664+
bool*isnull)
2665+
{
2666+
ExprEvalStep*fetchop=&state->steps[0];
2667+
ExprEvalStep*var=&state->steps[1];
2668+
ExprEvalStep*hashop=&state->steps[2];
2669+
FunctionCallInfofcinfo=hashop->d.hashdatum.fcinfo_data;
2670+
intattnum=var->d.var.attnum;
2671+
2672+
CheckOpSlotCompatibility(fetchop,econtext->ecxt_outertuple);
2673+
slot_getsomeattrs(econtext->ecxt_outertuple,fetchop->d.fetch.last_var);
2674+
2675+
fcinfo->args[0].value=econtext->ecxt_outertuple->tts_values[attnum];
2676+
fcinfo->args[0].isnull=econtext->ecxt_outertuple->tts_isnull[attnum];
2677+
2678+
if (!fcinfo->args[0].isnull)
2679+
{
2680+
*isnull= false;
2681+
returnDatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2682+
}
2683+
else
2684+
{
2685+
/* return NULL on NULL input */
2686+
*isnull= true;
2687+
return (Datum)0;
2688+
}
2689+
}
2690+
24872691
#if defined(EEO_USE_COMPUTED_GOTO)
24882692
/*
24892693
* Comparator used when building address->opcode lookup table for

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp