| From: | Heikki Linnakangas <hlinnaka(at)iki(dot)fi> |
|---|---|
| To: | Andres Freund <andres(at)anarazel(dot)de>, pgsql-hackers(at)postgresql(dot)org, Amit Langote <amitlangote09(at)gmail(dot)com>, Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, David Rowley <dgrowleyml(at)gmail(dot)com> |
| Subject: | Re: unnecessary executor overheads around seqscans |
| Date: | 2026-01-26 15:23:16 |
| Message-ID: | 2c266fc0-8cd0-41c3-bd28-a874c422d158@iki.fi |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On 23/01/2026 22:16, Andres Freund wrote:
> Hi,
>
> In [1] I was looking at the profile of a seqscan with a where clause that
> doesn't match any of the many rows. I was a bit saddened by where we were
> spending time.
>
>
> - The fetching of variables, as well as the null check of scandesc, in
> SeqNext() is repeated in every loop iteration of ExecScanExtended, despite
> that obviously not being required after the first iteration
>
> We could perhaps address this by moving the check to the callers of
> ExecScanExtended() or by extending ExecScanExtended to have an explicit
> beginscan callback that it calls after.
For context, we're talking about this in SeqNext:
> /*
> * get information from the estate and scan state
> */
> scandesc = node->ss.ss_currentScanDesc;
> estate = node->ss.ps.state;
> direction = estate->es_direction;
> slot = node->ss.ss_ScanTupleSlot;
Hmm. I guess the compiler doesn't know that the variables don't change
between calls, so it has to fetch them on every iteration. Passing them
through a 'const' pointer might give it clue, but I'm not sure how to
shoehorn that here.
Perhaps we should turn the ExecScanExtended() function inside out.
Instead of passing SeqNext as a callback to ExecScanExtended(), we would
have a function like this (for illustration purposes only, doesn't compile):
> /* ----------------------------------------------------------------
> * ExecSeqNextInline
> *
> * This is a workhorse for ExecSeqScan. It's inlined into
> * specialized implementations for cases where epqstate, qual,
> * projInfo are NULL or not.
> * ----------------------------------------------------------------
> */
> static pg_attribute_always_inline TupleTableSlot *
> ExecSeqScanInline(SeqScanState *node,
> EPQState *epqstate,
> ExprState *qual,
> ProjectionInfo *projInfo)
> {
> /*
> * get information from the estate and scan state
> */
> scandesc = node->ss.ss_currentScanDesc;
> estate = node->ss.ps.state;
> direction = estate->es_direction;
> slot = node->ss.ss_ScanTupleSlot;
>
> if (scandesc == NULL)
> {
> /*
> * We reach here if the scan is not parallel, or if we're serially
> * executing a scan that was planned to be parallel.
> */
> scandesc = table_beginscan(node->ss.ss_currentRelation,
> estate->es_snapshot,
> 0, NULL);
> node->ss.ss_currentScanDesc = scandesc;
> }
>
> for (;;)
> {
> /* do ExecScanFetch(), except for the call to SeqScanNext */
> slot = ExecScanFetchEPQ(...);
>
> /*
> * get the row next tuple from the table
> */
> if (slot == NULL)
> slot = table_scan_getnextslot(scandesc, direction, slot);
>
> if (slot == NULL)
> break;
>
> /*
> * Does it pass the quals? (This does the parts of ExecScanExtended()
> * after the ExecScanFetch() call)
> */
> slot = ExecScanProjectAndFilter(&node->ss, slot, qual, projInfo);
> if (slot)
> return slot;
> }
> return NULL;
> }
- Heikki
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Zsolt Parragi | 2026-01-26 15:36:30 | Re: meson: Make test output much more useful on failure (both in CI and locally) |
| Previous Message | Peter Eisentraut | 2026-01-26 15:09:00 | Re: Fix accidentally cast away qualifiers |