Skip to content

Commit 19b861f

Browse files
committed
Speedup WindowAgg code by moving uncommon code out-of-line
The code to calculate the frame offsets is only performed once per scan. Moving this code out of line gives a small (around 4-5%) speedup when testing with some CPUs. Other tested CPUs are indifferent to the change. Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Reviewed-by: Tatsuo Ishii <ishii@postgresql.org> Discussion: https://postgr.es/m/CAApHDvqPgFtwme2Zyf75BpMLwYr2mnUstDyPiP%3DEpudYuQTPPQ%40mail.gmail.com
1 parent 06421b0 commit 19b861f

File tree

1 file changed

+78
-62
lines changed

1 file changed

+78
-62
lines changed

src/backend/executor/nodeWindowAgg.c

Lines changed: 78 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,6 +2032,82 @@ update_grouptailpos(WindowAggState *winstate)
20322032
MemoryContextSwitchTo(oldcontext);
20332033
}
20342034

2035+
/*
2036+
* calculate_frame_offsets
2037+
* Determine the startOffsetValue and endOffsetValue values for the
2038+
* WindowAgg's frame options.
2039+
*/
2040+
static pg_noinline void
2041+
calculate_frame_offsets(PlanState *pstate)
2042+
{
2043+
WindowAggState *winstate = castNode(WindowAggState, pstate);
2044+
ExprContext *econtext;
2045+
int frameOptions = winstate->frameOptions;
2046+
Datum value;
2047+
bool isnull;
2048+
int16 len;
2049+
bool byval;
2050+
2051+
/* Ensure we've not been called before for this scan */
2052+
Assert(winstate->all_first);
2053+
2054+
econtext = winstate->ss.ps.ps_ExprContext;
2055+
2056+
if (frameOptions & FRAMEOPTION_START_OFFSET)
2057+
{
2058+
Assert(winstate->startOffset != NULL);
2059+
value = ExecEvalExprSwitchContext(winstate->startOffset,
2060+
econtext,
2061+
&isnull);
2062+
if (isnull)
2063+
ereport(ERROR,
2064+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2065+
errmsg("frame starting offset must not be null")));
2066+
/* copy value into query-lifespan context */
2067+
get_typlenbyval(exprType((Node *) winstate->startOffset->expr),
2068+
&len,
2069+
&byval);
2070+
winstate->startOffsetValue = datumCopy(value, byval, len);
2071+
if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS))
2072+
{
2073+
/* value is known to be int8 */
2074+
int64 offset = DatumGetInt64(value);
2075+
2076+
if (offset < 0)
2077+
ereport(ERROR,
2078+
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2079+
errmsg("frame starting offset must not be negative")));
2080+
}
2081+
}
2082+
2083+
if (frameOptions & FRAMEOPTION_END_OFFSET)
2084+
{
2085+
Assert(winstate->endOffset != NULL);
2086+
value = ExecEvalExprSwitchContext(winstate->endOffset,
2087+
econtext,
2088+
&isnull);
2089+
if (isnull)
2090+
ereport(ERROR,
2091+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2092+
errmsg("frame ending offset must not be null")));
2093+
/* copy value into query-lifespan context */
2094+
get_typlenbyval(exprType((Node *) winstate->endOffset->expr),
2095+
&len,
2096+
&byval);
2097+
winstate->endOffsetValue = datumCopy(value, byval, len);
2098+
if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS))
2099+
{
2100+
/* value is known to be int8 */
2101+
int64 offset = DatumGetInt64(value);
2102+
2103+
if (offset < 0)
2104+
ereport(ERROR,
2105+
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2106+
errmsg("frame ending offset must not be negative")));
2107+
}
2108+
}
2109+
winstate->all_first = false;
2110+
}
20352111

20362112
/* -----------------
20372113
* ExecWindowAgg
@@ -2061,68 +2137,8 @@ ExecWindowAgg(PlanState *pstate)
20612137
* rescan). These are assumed to hold constant throughout the scan; if
20622138
* user gives us a volatile expression, we'll only use its initial value.
20632139
*/
2064-
if (winstate->all_first)
2065-
{
2066-
int frameOptions = winstate->frameOptions;
2067-
Datum value;
2068-
bool isnull;
2069-
int16 len;
2070-
bool byval;
2071-
2072-
econtext = winstate->ss.ps.ps_ExprContext;
2073-
2074-
if (frameOptions & FRAMEOPTION_START_OFFSET)
2075-
{
2076-
Assert(winstate->startOffset != NULL);
2077-
value = ExecEvalExprSwitchContext(winstate->startOffset,
2078-
econtext,
2079-
&isnull);
2080-
if (isnull)
2081-
ereport(ERROR,
2082-
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2083-
errmsg("frame starting offset must not be null")));
2084-
/* copy value into query-lifespan context */
2085-
get_typlenbyval(exprType((Node *) winstate->startOffset->expr),
2086-
&len, &byval);
2087-
winstate->startOffsetValue = datumCopy(value, byval, len);
2088-
if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS))
2089-
{
2090-
/* value is known to be int8 */
2091-
int64 offset = DatumGetInt64(value);
2092-
2093-
if (offset < 0)
2094-
ereport(ERROR,
2095-
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2096-
errmsg("frame starting offset must not be negative")));
2097-
}
2098-
}
2099-
if (frameOptions & FRAMEOPTION_END_OFFSET)
2100-
{
2101-
Assert(winstate->endOffset != NULL);
2102-
value = ExecEvalExprSwitchContext(winstate->endOffset,
2103-
econtext,
2104-
&isnull);
2105-
if (isnull)
2106-
ereport(ERROR,
2107-
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2108-
errmsg("frame ending offset must not be null")));
2109-
/* copy value into query-lifespan context */
2110-
get_typlenbyval(exprType((Node *) winstate->endOffset->expr),
2111-
&len, &byval);
2112-
winstate->endOffsetValue = datumCopy(value, byval, len);
2113-
if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS))
2114-
{
2115-
/* value is known to be int8 */
2116-
int64 offset = DatumGetInt64(value);
2117-
2118-
if (offset < 0)
2119-
ereport(ERROR,
2120-
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2121-
errmsg("frame ending offset must not be negative")));
2122-
}
2123-
}
2124-
winstate->all_first = false;
2125-
}
2140+
if (unlikely(winstate->all_first))
2141+
calculate_frame_offsets(pstate);
21262142

21272143
/* We need to loop as the runCondition or qual may filter out tuples */
21282144
for (;;)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy