Re: show Heap Fetches in EXPLAIN for index-only scans - Mailing list pgsql-hackers

From Robert Haas
Subject Re: show Heap Fetches in EXPLAIN for index-only scans
Date
Msg-id CA+TgmoYt1bD8H31MMAGy8NkEhkea2HFwe4TE4NvCV1R-srs1Rg@mail.gmail.com
Whole thread Raw
In response to Re: show Heap Fetches in EXPLAIN for index-only scans  (Jeff Janes <jeff.janes@gmail.com>)
Responses Re: show Heap Fetches in EXPLAIN for index-only scans
List pgsql-hackers
On Sat, Jan 21, 2012 at 9:50 PM, Jeff Janes <jeff.janes@gmail.com> wrote:
> A review:
>
> [ review ]

Thanks.  Committed with hopefully-appropriate revisions.

> As a side-note, I noticed that I needed to run vacuum twice in a row
> to get the Heap Fetches to drop to zero.  I vaguely recall that only
> one vacuum was needed when ios first went in (and I had instrumented
> it to elog heap-fetches).  Does anyone know if this the expected
> consequence of one of the recent changes we made to vacuum?

No, that's not expected.  The change we made to vacuum was to skip
pages that are busy - but it shouldn't be randomly skipping pages for
no reason.  I can reproduce what you're observing, though:

[rhaas 16384]$ pg_filedump 16411 | grep TLI.*Flags | grep -v 'Flags: 0x0004'TLI: 0x0001  Prune XID: 0x00000000  Flags:
0x0005(HAS_FREE_LINES)TLI: 0x0001  Prune XID: 0x00000000  Flags: 0x0005 (HAS_FREE_LINES) 

After updating a row in the table and checkpointing, the page the rows
was on is marked full and the page that gets the new version becomes
not-all-visible:

[rhaas 16384]$ pg_filedump 16411 | grep TLI.*Flags | grep -v 'Flags: 0x0004'TLI: 0x0001  Prune XID: 0x000003fb  Flags:
0x0003(HAS_FREE_LINES|PAGE_FULL)TLI: 0x0001  Prune XID: 0x00000000  Flags: 0x0001 (HAS_FREE_LINES) 

Now I vacuum the relation and checkpoint, and the page the *new*
relation is on becomes all-visible:

[rhaas 16384]$ pg_filedump 16411 | grep TLI.*Flags | grep -v 'Flags: 0x0004'TLI: 0x0001  Prune XID: 0x00000000  Flags:
0x0001(HAS_FREE_LINES)TLI: 0x0001  Prune XID: 0x00000000  Flags: 0x0005 (HAS_FREE_LINES) 

Now I vacuum it again and checkpoint, and now the old page also
becomes all-visible:

[rhaas 16384]$ pg_filedump 16411 | grep TLI.*Flags | grep -v 'Flags: 0x0004'TLI: 0x0001  Prune XID: 0x00000000  Flags:
0x0005(HAS_FREE_LINES)TLI: 0x0001  Prune XID: 0x00000000  Flags: 0x0005 (HAS_FREE_LINES) 

But it seems to me that this is expected (if non-optimal) behavior.
Only the first pass of vacuum knows how to mark pages all-visible.
After the update, the first pass of the first vacuum sees a dead tuple
on the old page and truncates it to a dead line pointer.  When it
comes to the new page, it observes that the page is now all-visible
and marks it so.  It then does index vacuuming and returns to the
first page, marking the dead line pointer unused.  But during this
second visit to the old page, there's no possibility of marking the
page as all-visible, because the code doesn't know how to do that.
The next vacuum's first pass, however, can do so, because there are no
longer any dead tuples on the page.

We could fix this by modifying lazy_vacuum_page(): since we have to
dirty the buffer anyway, we could recheck whether all the remaining
tuples on the page are now all-visible, and if so set the visibility
map bit.  This is probably desirable even apart from index-only scans,
because it will frequently save the next vacuum the cost of reading,
dirtying, and writing extra pages.  There will be some incremental CPU
cost, but that seems likely to be more than repaid by the I/O savings.

Thoughts?  Should we do this at all?  If so, should we squeeze it into
9.2 or leave it for 9.3?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


pgsql-hackers by date:

Previous
From: Greg Smith
Date:
Subject: Re: Vacuum rate limit in KBps
Next
From: Robert Haas
Date:
Subject: Re: Group commit, revised