Re: WIP: Faster Expression Processing v4

From: Andres Freund <andres(at)anarazel(dot)de>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-hackers(at)postgresql(dot)org, Heikki Linnakangas <hlinnaka(at)iki(dot)fi>, Tomas Vondra <tomas(dot)vondra(at)2ndquadrant(dot)com>
Subject: Re: WIP: Faster Expression Processing v4
Date: 2017-03-16 00:28:31
Message-ID: 20170316002831.55jqq5knpu5szaxb@alap3.anarazel.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 2017-03-15 18:48:28 -0400, Tom Lane wrote:
> Andres Freund <andres(at)anarazel(dot)de> writes:
> > On 2017-03-15 18:16:57 -0400, Tom Lane wrote:
> >> [ scratches head... ] What deforming logic do you think I'm proposing
> >> removing?
>
> > I thought you were suggesting that we don't do the get_last_attnums (and
> > inlined version in the isSimpleVar case) at execution time anymore,
> > instead relying on logic in the planner to know how much to deform ahead
> > of time. Then we'd do slot_getsomeattrs in the appropriate places. But
> > I understood you suggesting to do so only in scan nodes - which doesn't
> > seem sufficient, due to the use of materialized / minimal tuples in
> > other types of nodes. Did I misunderstand?
>
> We would need to do it anywhere that we might be projecting from a
> materialized tuple, I suppose. From the planner's standpoint it would be
> about as easy to do this for all plan nodes as only selected ones.

Yea.

> Anyway the core point here seems to be that skipping ExecProject misses a
> bet because the underlying tuple doesn't get disassembled. A quick-hack
> way of seeing if this helps might be to do slot_getallattrs in the places
> where we skip ExecProject.
> I'm not sure we'd want that as a permanent
> solution, because it's possible that it extracts columns not actually
> needed, but it should at least move the hotspot in your example case.

Hm, that could hurt pretty badly if we actually only access the first
few columns.

I wonder if we shouldn't essentially get rid of all slot_getattr()
calls, and replace them with one slot_getsomeattrs() and then direct
tts_values/nulls access. Where we compute the column number is then
essentially a separate discussion.

Looking around most of them seem to access multiple columns, and several
of them probably can't conveniently done via the planner:

src/backend/catalog/partition.c
1635: datum = slot_getattr(slot, keycol, &isNull);

acesses all the partitioned columns and has convenient location to
compute column to deform to (RelationGetPartitionDispatchInfo).

src/backend/catalog/index.c
1797: iDatum = slot_getattr(slot, keycol, &isNull);

acesses all the partitioned columns and has convenient location to
compute column to deform to (BuildIndexInfo).

src/backend/utils/adt/orderedsetaggs.c
1196: Datum d = slot_getattr(slot, nargs + 1, &isnull);
1359: Datum d = slot_getattr(slot, nargs + 1, &isnull);

no benefit.

src/backend/executor/nodeMergeAppend.c
246: datum1 = slot_getattr(s1, attno, &isNull1);
247: datum2 = slot_getattr(s2, attno, &isNull2);

accesses all columns in the sort key, convenient place to prepare
(ExecInitMergeAppend).

src/backend/executor/execQual.c
594: * caught inside slot_getattr). What we have to check for here is the
600: * Note: we allow a reference to a dropped attribute. slot_getattr will
637: return slot_getattr(slot, attnum, isNull);
676: return slot_getattr(slot, attnum, isNull);
1681: return slot_getattr(fcache->funcResultSlot, 1, isNull);

Already converted in proposed expression evaluation patch.

src/backend/executor/nodeSubplan.c
367: dvalue = slot_getattr(slot, 1, &disnull);
395: prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
565: prmdata->value = slot_getattr(slot, col,
1015: dvalue = slot_getattr(slot, 1, &disnull);

Accesses all params, convenient location to compute column number
(ExecInitSubPlan).

src/backend/executor/execCurrent.c
186: /* Use slot_getattr to catch any possible mistakes */
188: DatumGetObjectId(slot_getattr(scanstate->ss_ScanTupleSlot,
193: DatumGetPointer(slot_getattr(scanstate->ss_ScanTupleSlot,

Accesses only system columns.

src/backend/executor/nodeSetOp.c
107: flag = DatumGetInt32(slot_getattr(inputslot,

Not an actual column.

src/backend/executor/nodeGatherMerge.c
678: datum1 = slot_getattr(s1, attno, &isNull1);
679: datum2 = slot_getattr(s2, attno, &isNull2);

Same as mergeAppend (huh, why did we copy this code), i.e. beneficial.

src/backend/executor/functions.c
970: value = slot_getattr(slot, 1, &(fcinfo->isnull));

no benefit.

src/backend/executor/execJunk.c
253: return slot_getattr(slot, attno, isNull);

no benefit.

src/backend/executor/nodeNestloop.c
136: prm->value = slot_getattr(outerTupleSlot,

accesses all future param values, convenient place to compute column
number.

src/backend/executor/execGrouping.c
100: attr1 = slot_getattr(slot1, att, &isNull1);
102: attr2 = slot_getattr(slot2, att, &isNull2);
170: attr1 = slot_getattr(slot1, att, &isNull1);
175: attr2 = slot_getattr(slot2, att, &isNull2);
501: attr = slot_getattr(slot, att, &isNull);

accesses all grouped-on values, but only some have a convenient place to
compute column number.

src/backend/access/common/printtup.c
545: attr = slot_getattr(slot, i + 1, &isnull);

Debug routine.

contrib/postgres_fdw/postgres_fdw.c
3213: value = slot_getattr(slot, attnum, &isnull);

Computes all parameter values, convenient-ish place to compute colun
number.

- Andres

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Simon Riggs 2017-03-16 00:31:55 Re: Patch to improve performance of replay of AccessExclusiveLock
Previous Message Tom Lane 2017-03-16 00:09:03 Re: WIP: Faster Expression Processing v4