Thread

Commits

  1. Count updates that move row to a new page.

  1. Add n_tup_newpage_upd to pg_stat table views

    Corey Huinker <corey.huinker@gmail.com> — 2023-01-27T23:23:39Z

    This patch adds the n_tup_newpage_upd to all the table stat views.
    
    Just as we currently track HOT updates, it should be beneficial to track
    updates where the new tuple cannot fit on the existing page and must go to
    a different one.
    
    Hopefully this can give users some insight as to whether their current
    fillfactor settings need to be adjusted.
    
    My chosen implementation replaces the hot-update boolean with an
    update_type which is currently a three-value enum. I favored that
    only slightly over adding a separate newpage-update boolean because the two
    events are mutually exclusive and fewer parameters is less overhead and one
    less assertion check. The relative wisdom of this choice may not come to
    light until we add a new measurement and see whether that new measurement
    overlaps either is-hot or is-new-page.
    
  2. Re: Add n_tup_newpage_upd to pg_stat table views

    Andres Freund <andres@anarazel.de> — 2023-01-27T23:55:14Z

    Hi,
    
    On 2023-01-27 18:23:39 -0500, Corey Huinker wrote:
    > This patch adds the n_tup_newpage_upd to all the table stat views.
    >
    > Just as we currently track HOT updates, it should be beneficial to track
    > updates where the new tuple cannot fit on the existing page and must go to
    > a different one.
    
    I like that idea.
    
    
    I wonder if it's quite detailed enough - we can be forced to do out-of-page
    updates because we actually are out of space, or because we reach the max
    number of line pointers we allow in a page. HOT pruning can't remove dead line
    pointers, so that doesn't necessarily help.
    
    Which e.g. means that:
    
    > Hopefully this can give users some insight as to whether their current
    > fillfactor settings need to be adjusted.
    
    Isn't that easy, because you can have a page with just a visible single tuple
    on, but still be unable to do a same-page update. The fix instead is to VACUUM
    (more aggressively).
    
    
    OTOH, just seeing that there's high percentage "out-of-page updates" provides
    more information than we have right now.  And the alternative would be to add
    yet another counter.
    
    
    Similarly, it's a bit sad that we can't distinguish between the number of
    potential-HOT out-of-page updates and the other out-of-page updates. But
    that'd mean even more counters.
    
    
    I guess we could try to add tracepoints to allow to distinguish between those
    cases instead? Not a lot of people use those though.
    
    
    
    > @@ -372,8 +372,11 @@ pgstat_count_heap_update(Relation rel, bool hot)
    >  		pgstat_info->trans->tuples_updated++;
    >
    >  		/* t_tuples_hot_updated is nontransactional, so just advance it */
    > -		if (hot)
    > +		if (hut == PGSTAT_HEAPUPDATE_HOT)
    >  			pgstat_info->t_counts.t_tuples_hot_updated++;
    > +		else if (hut == PGSTAT_HEAPUPDATE_NEW_PAGE)
    > +			pgstat_info->t_counts.t_tuples_newpage_updated++;
    > +
    >  	}
    >  }
    >
    
    I think this might cause some trouble for existing monitoring setups after an
    upgrade. Suddenly the number of updates will appear way lower than
    before... And if we end up eventually distinguishing between different reasons
    for out-of-page updates, or hot/non-hot out-of-page that'll happen again.
    
    I wish we'd included HOT updates in the total number of updates, and just kept
    HOT updates a separate counter that'd always be less than updates in total.
    
    
    From that angle: Perhaps it'd be better to have counter for how many times a
    page is found to be full during an update?
    
    
    > --- a/src/backend/access/heap/heapam.c
    > +++ b/src/backend/access/heap/heapam.c
    > @@ -3155,7 +3155,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
    >  				pagefree;
    >  	bool		have_tuple_lock = false;
    >  	bool		iscombo;
    > -	bool		use_hot_update = false;
    > +	PgStat_HeapUpdateType update_type = PGSTAT_HEAPUPDATE_NON_HOT;
    > +
    >  	bool		key_intact;
    >  	bool		all_visible_cleared = false;
    >  	bool		all_visible_cleared_new = false;
    > @@ -3838,10 +3839,11 @@ l2:
    >  		 * changed.
    >  		 */
    >  		if (!bms_overlap(modified_attrs, hot_attrs))
    > -			use_hot_update = true;
    > +			update_type = PGSTAT_HEAPUPDATE_HOT;
    >  	}
    >  	else
    >  	{
    > +		update_type = PGSTAT_HEAPUPDATE_NEW_PAGE;
    >  		/* Set a hint that the old page could use prune/defrag */
    >  		PageSetFull(page);
    >  	}
    > @@ -3875,7 +3877,7 @@ l2:
    >  	 */
    >  	PageSetPrunable(page, xid);
    >
    > -	if (use_hot_update)
    > +	if (update_type == PGSTAT_HEAPUPDATE_HOT)
    
    It's a bit weird that heap_update() uses a pgstat type to decide what to
    do. But not sure there's a much better alternative.
    
    Greetings,
    
    Andres Freund
    
    
    
    
  3. Re: Add n_tup_newpage_upd to pg_stat table views

    Peter Geoghegan <pg@bowt.ie> — 2023-01-28T01:59:32Z

    On Fri, Jan 27, 2023 at 3:55 PM Andres Freund <andres@anarazel.de> wrote:
    > I wonder if it's quite detailed enough - we can be forced to do out-of-page
    > updates because we actually are out of space, or because we reach the max
    > number of line pointers we allow in a page. HOT pruning can't remove dead line
    > pointers, so that doesn't necessarily help.
    
    It would be hard to apply that kind of information, I suspect. Maybe
    it's still worth having, though.
    
    > Similarly, it's a bit sad that we can't distinguish between the number of
    > potential-HOT out-of-page updates and the other out-of-page updates. But
    > that'd mean even more counters.
    
    ISTM that it would make more sense to do that at the index level
    instead. It wouldn't be all that hard to teach ExecInsertIndexTuples()
    to remember whether each index received the indexUnchanged hint used
    by bottom-up deletion, which is approximately the same thing, but
    works at the index level.
    
    This is obviously more useful, because you have index-granularity
    information that can guide users in how to index to maximize the
    number of HOT updates. And, even if changing things around didn't lead
    to the hoped-for improvement in the rate of HOT updates, it would at
    least still allow the indexes on the table to use bottom-up deletion
    more often, on average.
    
    Admittedly this has some problems. The index_unchanged_by_update()
    logic probably isn't as sophisticated as it ought to be because it's
    driven by the statement-level extraUpdatedCols bitmap set, and not a
    per-tuple test, like the HOT safety test in heap_update() is.
    But...that should probably be fixed anyway.
    
    > I think this might cause some trouble for existing monitoring setups after an
    > upgrade. Suddenly the number of updates will appear way lower than
    > before... And if we end up eventually distinguishing between different reasons
    > for out-of-page updates, or hot/non-hot out-of-page that'll happen again.
    
    Uh...no it won't? The new counter is totally independent of the existing
    HOT counter, and the transactional all-updates counter. It's just that
    there is an enum that encodes which of the two non-transactional "sub
    counters" to use (either for HOT updates or new-page-migration
    updates).
    
    > I wish we'd included HOT updates in the total number of updates, and just kept
    > HOT updates a separate counter that'd always be less than updates in total.
    
    Uh...we did in fact do it that way to begin with?
    
    > From that angle: Perhaps it'd be better to have counter for how many times a
    > page is found to be full during an update?
    
    Didn't Corey propose a patch to add just that? Do you mean something
    more specific, like a tracker for when an UPDATE leaves a page full,
    without needing to go to a new page itself?
    
    If so, then that does require defining what that really means, because
    it isn't trivial. Do you assume that all updates have a successor
    version that is equal in size to that of the UPDATE that gets counted
    by this hypothetical other counter of yours?
    
    --
    Peter Geoghegan
    
    
    
    
  4. Re: Add n_tup_newpage_upd to pg_stat table views

    Andres Freund <andres@anarazel.de> — 2023-01-28T02:44:32Z

    Hi,
    
    On 2023-01-27 17:59:32 -0800, Peter Geoghegan wrote:
    > > I think this might cause some trouble for existing monitoring setups after an
    > > upgrade. Suddenly the number of updates will appear way lower than
    > > before... And if we end up eventually distinguishing between different reasons
    > > for out-of-page updates, or hot/non-hot out-of-page that'll happen again.
    > 
    > Uh...no it won't? The new counter is totally independent of the existing
    > HOT counter, and the transactional all-updates counter. It's just that
    > there is an enum that encodes which of the two non-transactional "sub
    > counters" to use (either for HOT updates or new-page-migration
    > updates).
    >
    > > I wish we'd included HOT updates in the total number of updates, and just kept
    > > HOT updates a separate counter that'd always be less than updates in total.
    > 
    > Uh...we did in fact do it that way to begin with?
    
    Sorry, I misread the diff, and then misremembered some old issue.
    
    
    > > From that angle: Perhaps it'd be better to have counter for how many times a
    > > page is found to be full during an update?
    > 
    > Didn't Corey propose a patch to add just that? Do you mean something
    > more specific, like a tracker for when an UPDATE leaves a page full,
    > without needing to go to a new page itself?
    
    Nope, I just had a brainfart.
    
    
    > > Similarly, it's a bit sad that we can't distinguish between the number of
    > > potential-HOT out-of-page updates and the other out-of-page updates. But
    > > that'd mean even more counters.
    > 
    > ISTM that it would make more sense to do that at the index level
    > instead. It wouldn't be all that hard to teach ExecInsertIndexTuples()
    > to remember whether each index received the indexUnchanged hint used
    > by bottom-up deletion, which is approximately the same thing, but
    > works at the index level.
    
    I don't think that'd make it particularly easy to figure out how often
    out-of-space causes non-HOT updates to go out of page, and how often it causes
    potential HOT updates to go out of page.  If you just have a single index,
    it's not too hard, but after that seems decidedly nontrival.
    
    But I might just be missing what you're suggesting.
    
    
    Greetings,
    
    Andres Freund
    
    
    
    
  5. Re: Add n_tup_newpage_upd to pg_stat table views

    Peter Geoghegan <pg@bowt.ie> — 2023-01-28T02:51:09Z

    On Fri, Jan 27, 2023 at 6:44 PM Andres Freund <andres@anarazel.de> wrote:
    > I don't think that'd make it particularly easy to figure out how often
    > out-of-space causes non-HOT updates to go out of page, and how often it causes
    > potential HOT updates to go out of page.  If you just have a single index,
    > it's not too hard, but after that seems decidedly nontrival.
    >
    > But I might just be missing what you're suggesting.
    
    It would be useless for that, of course. But it would be a good proxy
    for what specific indexes force non-hot updates due to HOT safety
    issues. This would work independently of the issue of what's going on
    in the heap. That matters too, of course, but in practice the main
    problem is likely the specific combination of indexes and updates.
    (Maybe it would just be an issue with heap fill factor, at times, but
    even then you'd still want to rule out basic HOT safety issues first.)
    
    If you see one particular index that gets a far larger number of
    non-hot updates that are reported as "logical changes to the indexed
    columns", then dropping that index has the potential to make the HOT
    update situation far better.
    
    --
    Peter Geoghegan
    
    
    
    
  6. Re: Add n_tup_newpage_upd to pg_stat table views

    Corey Huinker <corey.huinker@gmail.com> — 2023-01-30T18:40:15Z

    On Fri, Jan 27, 2023 at 6:55 PM Andres Freund <andres@anarazel.de> wrote:
    
    > Hi,
    >
    > On 2023-01-27 18:23:39 -0500, Corey Huinker wrote:
    > > This patch adds the n_tup_newpage_upd to all the table stat views.
    > >
    > > Just as we currently track HOT updates, it should be beneficial to track
    > > updates where the new tuple cannot fit on the existing page and must go
    > to
    > > a different one.
    >
    > I like that idea.
    >
    >
    > I wonder if it's quite detailed enough - we can be forced to do out-of-page
    > updates because we actually are out of space, or because we reach the max
    > number of line pointers we allow in a page. HOT pruning can't remove dead
    > line
    > pointers, so that doesn't necessarily help.
    >
    
    I must be missing something, I only see the check for running out of space,
    not the check for exhausting line pointers. I agree dividing them would be
    interesting.
    
    
    
    > Similarly, it's a bit sad that we can't distinguish between the number of
    > potential-HOT out-of-page updates and the other out-of-page updates. But
    > that'd mean even more counters.
    >
    
    I wondered that too, but the combinations of "would have been HOT but not
    no space" and "key update suggested not-HOT but it was id=id so today's
    your lucky HOT" combinations started to get away from me.
    
    I wondered if there was interest in knowing if the tuple had to get
    TOASTed, and further wondered if we would be interested in the number of
    updates that had to wait on a lock. Again, more counters.
    
  7. Re: Add n_tup_newpage_upd to pg_stat table views

    Andres Freund <andres@anarazel.de> — 2023-01-30T18:45:28Z

    Hi,
    
    On 2023-01-30 13:40:15 -0500, Corey Huinker wrote:
    > I must be missing something, I only see the check for running out of space,
    > not the check for exhausting line pointers. I agree dividing them would be
    > interesting.
    
    See PageGetHeapFreeSpace(), particularly the header comment and the
    MaxHeapTuplesPerPage check.
    
    
    > > Similarly, it's a bit sad that we can't distinguish between the number of
    > > potential-HOT out-of-page updates and the other out-of-page updates. But
    > > that'd mean even more counters.
    >
    > I wondered that too, but the combinations of "would have been HOT but not
    > no space" and "key update suggested not-HOT but it was id=id so today's
    > your lucky HOT" combinations started to get away from me.
    
    Not sure I follow the second part. Are you just worried about explaining when
    a HOT update is possible?
    
    
    > I wondered if there was interest in knowing if the tuple had to get
    > TOASTed, and further wondered if we would be interested in the number of
    > updates that had to wait on a lock. Again, more counters.
    
    Those seem a lot less actionable / related to the topic at hand to me.
    
    Greetings,
    
    Andres Freund
    
    
    
    
  8. Re: Add n_tup_newpage_upd to pg_stat table views

    Peter Geoghegan <pg@bowt.ie> — 2023-03-17T22:22:54Z

    On Fri, Jan 27, 2023 at 3:23 PM Corey Huinker <corey.huinker@gmail.com> wrote:
    > This patch adds the n_tup_newpage_upd to all the table stat views.
    
    I think that this is pretty close to being committable already.
    
    I'll move on that early next week, barring any objections.
    
    -- 
    Peter Geoghegan
    
    
    
    
  9. Re: Add n_tup_newpage_upd to pg_stat table views

    Peter Geoghegan <pg@bowt.ie> — 2023-03-23T00:14:08Z

    On Fri, Mar 17, 2023 at 3:22 PM Peter Geoghegan <pg@bowt.ie> wrote:
    > I think that this is pretty close to being committable already.
    
    Attached revision has some small tweaks by me. Going to commit this
    revised version tomorrow morning.
    
    Changes:
    
    * No more dedicated struct to carry around the type of an update.
    
    We just use two boolean arguments to the pgstats function instead. The
    struct didn't seem to be adding much, and it was distracting to track
    the information this way within heap_update().
    
    * Small adjustments to the documentation.
    
    Nearby related items were tweaked slightly to make everything fit
    together a bit better. For example, the description of n_tup_hot_upd
    is revised to make it obvious that n_tup_hot_upd counts row updates
    that can never get counted under the new n_tup_newpage_upd counter.
    
    --
    Peter Geoghegan
    
  10. Re: Add n_tup_newpage_upd to pg_stat table views

    Michael Paquier <michael@paquier.xyz> — 2023-03-23T00:24:12Z

    On Wed, Mar 22, 2023 at 05:14:08PM -0700, Peter Geoghegan wrote:
    > * Small adjustments to the documentation.
    > 
    > Nearby related items were tweaked slightly to make everything fit
    > together a bit better. For example, the description of n_tup_hot_upd
    > is revised to make it obvious that n_tup_hot_upd counts row updates
    > that can never get counted under the new n_tup_newpage_upd counter.
    
    @@ -168,6 +168,7 @@ typedef struct PgStat_TableCounts
            PgStat_Counter t_tuples_updated;
            PgStat_Counter t_tuples_deleted;
            PgStat_Counter t_tuples_hot_updated;
    +       PgStat_Counter t_tuples_newpage_updated;
            bool            t_truncdropped;
    
    I have in the works something that's going to rename these fields to
    not have the "t_" prefix anymore, to ease some global refactoring in
    pgstatfuncs.c so as we have less repetitive code with the functions 
    that grab these counters.  I don't think that's something you need to
    name without the prefix here, just a FYI that this is going to be
    immediately renamed ;)
    --
    Michael
    
  11. Re: Add n_tup_newpage_upd to pg_stat table views

    Corey Huinker <corey.huinker@gmail.com> — 2023-03-23T05:38:42Z

    >
    >
    > * No more dedicated struct to carry around the type of an update.
    >
    > We just use two boolean arguments to the pgstats function instead. The
    > struct didn't seem to be adding much, and it was distracting to track
    > the information this way within heap_update().
    >
    
    That's probably a good move, especially if we start tallying updates that
    use TOAST.
    
  12. Re: Add n_tup_newpage_upd to pg_stat table views

    Peter Geoghegan <pg@bowt.ie> — 2023-03-23T18:18:08Z

    On Wed, Mar 22, 2023 at 10:38 PM Corey Huinker <corey.huinker@gmail.com> wrote:
    > That's probably a good move, especially if we start tallying updates that use TOAST.
    
    Okay, pushed.
    
    Thanks
    -- 
    Peter Geoghegan