Re: Expanding HOT updates for expression and partial indexes - Mailing list pgsql-hackers

From Greg Burd
Subject Re: Expanding HOT updates for expression and partial indexes
Date
Msg-id 91f4dbe2-21ed-49f3-bebe-270f9bbec9d5@app.fastmail.com
Whole thread Raw
In response to Re: Expanding HOT updates for expression and partial indexes  (Nathan Bossart <nathandbossart@gmail.com>)
List pgsql-hackers
On Thu, Mar 12, 2026, at 4:33 PM, Nathan Bossart wrote:
> On Wed, Mar 11, 2026 at 11:51:03AM -0400, Greg Burd wrote:
>> 0002 - This patch plugs a hole (bug?) in ExecGetAllUpdatedCols() which is
>> triggered by an existing test in tsearch.sql and the
>> tsvector_update_trigger().  That trigger uses heap_modify_tuple() to
>> change an indexed attribute that is not discovered by
>> ExecGetAllUpdatedCols(), which seems odd to me at best and at worst wrong
>> (or even a potential security issue).  This patch finds and adds columns
>> that are updated into the Bitmapset returned by ExecGetAllUpdatedCols().
>> The patch includes a helper function ExecCompareSlotAttrs() that will be
>> used in follow-on patches as well.
>
> I just looked at this one for now.

Hey Nathan!

Thanks for taking the time to review 0002.

>> The net is that the functions like HeapDetermineColumnsInfo() have to
>> scan all indexed attributes for changes rather than being able to first
>> reduce the indexed set by intersecting it with the set of attributes
>> known to be potentially updated.
>
> I noticed the patch doesn't update HeapDetermineColumnsInfo() accordingly.
> Is that intended?

Yes, that is intended.  The 0002 patch is bug fix that I'd hidden along with what is now 0003, I pulled it out for
clarityand to discuss independent of the other changes.
 

>> This commit introduces ExecCompareSlotAttrs() as a utility function to
>> identify those attributes that have changed.  It compares a subset of
>> attributes between two TupleTableSlots and returns a Bitmapset of
>> attributes that differ.
>
> Hm.  Most of this new function looks duplicated from
> HeapDetermineColumnsInfo(), so IIUC this commit effectively adds another
> scan through all the attributes.  Does this produce noticeably more
> overhead?

Yes, it appears similar to that for a reason but it differs in one key way.  It compares TupleTableSlots, not
HeapTuples.

The commit doesn't add another scan, the new code only scans the attributes that ExecGetAllUpdatedCols() didn't pick up
earlierand have cached for us at this point.  The intersection between that set and what is indexed is almost always
theNULL set because most UPDATEs don't invoke functions via triggers that modify indexed columns using
heap_modify_tuple()directly.  But, notably there is the case in tsearch.sql that does.
 

This introduces almost no net new overhead and when it does in fact do some work it's doing no more than what was done
beforein HeapDetermineColumnsInfo().
 

>> It would be nice to integrate this into HeapDetermineColumnsInfo(),
>> however it would be a layering violation given that it is within
>> heap_update().
>
> It'd be good to understand whether the current behavior is intentional or
> just a happy accident.  I found commit 2fd8685e7f, which looks like it was
> intended as a prerequisite for the WARM feature (which I don't think was
> ever committed).  And it seems to have scanned through all indexed columns
> when HOT was first introduced in commit 282d2a03dd.

Hard to tell if it was accidental or intentional, more digging required, but I'd bet that others poking in this area
noticedthe test failure and didn't connect the dots fully and just assumed best practice was to scan all indexed
columns,even ones that could not have been updated at all.
 

Honestly, if we wrote this section from scratch again today I'm better it'd be closer to where my patch takes us than
not.

> I'm also curious whether anything else could modify columns that won't be
> discovered by ExecGetAllUpdatedCols().  Having HeapDetermineColumnsInfo()
> scan everything seems like a defense against such things, which is perhaps
> why you've left it unchanged in the patch.  I haven't looked into 0003 yet.
> Is 0002 a prerequisite for that or a separate fix?

Other than the heap_modify_tuple() calls I don't know of something that allows for direct changes but that doesn't
matter,0002 will scan and pick up those attributes even if we introduce a new modification path in the future (as
intended).

HeapDetermineColumnsInfo() can't call ExecGetAllUpdatedCols() because that function needs resultRelInfo/EState both not
availableinside heap (table AM) calls.  Also, the new helper compares TTS, not HeapTuples, which is what we have in
heapam_tuple_update(),so not an option
 

0002 is a both a bug fix (IMO) and a pre-req for 0003 because in the next patch we use the new ExecCompareSlotAttrs()
functionfrom within the executor ahead of calling into ExecUpdate().
 

> -- 
> nathan

Thanks for your time and comments, let me know if you have more. :)

best.

-greg



pgsql-hackers by date:

Previous
From: Andres Freund
Date:
Subject: Re: Why clearing the VM doesn't require registering vm buffer in wal record
Next
From: Greg Sabino Mullane
Date:
Subject: Re: [PATCH] libpq: try all addresses for a host before moving to next on target_session_attrs mismatch