Re: [HACKERS] Surprising dead_tuple_count from pgstattuple

2010-08-10 Thread Gordon Shannon

After much code reading, testing, and using the extremely handy pageinspect
contrib to look at pages, here's what I believe is happening. I am not
attempting to describe every possible scenario, only this one test path. 
Following my short test scenario above...

- Inserted rows get line pointers with status 1 (LP_NORMAL)

- When I do the 100 row delete, those rows stay status 1, but get their
t_xmax set, indicating they were deleted.

- When I do the next 200 row delete, those rows also get their t_xmax set.  

- As a side-effect to the deletion, the "hot prune" feature kicks in.  The 2
pages in question were processed by a call to heap_page_prune, which set the
line pointers of the previous 100 deleted rows to 3 (LP_DEAD).  Now I have
100 LP_DEAD and 200 LP_NORMAL with xmax set.

- When I do the vacuum, all 300 are "vacuumed" -- line pointer set to status
0 (LP_UNUSED).

- Because my table has no indexes, lazy_scan_heap calls lazy_vacuum_page
directly for each block, and reports the variable tups_vacuumed ("removed
200 row versions in 2 pages").  However, tups_vacuumed is computed without
counting the 100 LP_DEAD tuples, because per the code comment, it thinks to
do so would be double-counting. Perhaps the output should say something
like:

removed 300 row versions (200 were recently deleted and 100 were 
previously
deleted).

Whatever the phrasing, I don't know why 200 is the most significant number
here, and 300 isn't mentioned at all.

- If my table did have indexes, as in the original test case of this thread,
then the "removed xxx row version in yyy pages" message comes from
lazy_vacuum_heap instead.  However, instead of using tups_vacuumed, this
code reports the actual number of tuples actually set to status 0. 

I would like to respectfully suggest that the vacuum output line "removed xx
row versions in yy pages" should show the same counts regardless of whether
or not there's an index on the table. I would suggest that the value
reported by lazy_vacuum_heap is correct, and is what I would expect to see. 
I think it would be fine if it also reports the breakdown of LP_DEAD vs
LP_NORMAL tuples vacuumed, if that is deemed useful.

Regarding the output of pgstattuple, via the call to
HeapTupleSatisfiesVisibility, it appears that this simply returns true for
these hot-pruned LP_DEAD tuples, skewing the counts accordingly.

Does that make sense?

-- 
View this message in context: 
http://postgresql.1045698.n5.nabble.com/Surprising-dead-tuple-count-from-pgstattuple-tp2266955p2471232.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Surprising dead_tuple_count from pgstattuple

2010-08-07 Thread Gordon Shannon

I think this simple test highlights the question well.

--
create temporary table t(x int) with (autovacuum_enabled=off);
insert into t select x from generate_series(1,1,1)x;
vacuum verbose t;
select dead_tuple_count from pgstattuple('t');--> 0
delete from t where x <= 100;
select dead_tuple_count from pgstattuple('t');--> 100
delete from t where x <= 300;
select dead_tuple_count from pgstattuple('t');--> 200 (not 300)
vacuum verbose t;
vacuum verbose t;
select dead_tuple_count from pgstattuple('t');--> 0
drop table t;
--

When we get to the 2 vacuums at the end, I expect it to vacuum 300 rows, but
it only appears to vacuum 200...

vacuum verbose t;
psql:test:15: INFO:  vacuuming "pg_temp_2.t"
psql:test:15: INFO:  "t": removed 200 row versions in 2 pages
psql:test:15: INFO:  "t": found 200 removable, 9700 nonremovable row
versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 0 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
Time: 69.792 ms

Yet, the next vacuum reports that it found 300 unused item pointers. So they
were all vacuumed by somebody.

psql:test:16: INFO:  vacuuming "pg_temp_2.t"
psql:test:16: INFO:  "t": found 0 removable, 7158 nonremovable row versions
in 33 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 300 unused item pointers.
0 pages are entirely empty.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
Time: 38.436 ms

So, I guess my real question here is, what happened to the "missing" 100
items?  If it was HOT prune, can anyone summarize what that does?

Thanks!
-- 
View this message in context: 
http://postgresql.1045698.n5.nabble.com/Surprising-dead-tuple-count-from-pgstattuple-tp2266955p2267745.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] Surprising dead_tuple_count from pgstattuple

2010-08-06 Thread Gordon Shannon


Robert Haas wrote:
> 
> My thought would be "is autovacuum running in the background in
> between these commands?".
> 

That's a good thought, but no, autovacuum_vacuum_scale_factor is set to 0.2,
meaning that over 1 million dead tuples are necessary for autovacuum. 
Besides, if autovacuum had run, I think the pg_stat_user_tables.n_dead_tup
would have reset to zero, as it did after my manual vacuum.

Regarding HOT prune, I never did any updates, so I think there couldn't be
any HOT tuples.  Or does HOT prune do more than that?
-- 
View this message in context: 
http://postgresql.1045698.n5.nabble.com/Surprising-dead-tuple-count-from-pgstattuple-tp2266955p2267263.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] Surprising dead_tuple_count from pgstattuple

2010-08-06 Thread Gordon Shannon

This is an expansion of the question I posed in this thread:

http://postgresql.1045698.n5.nabble.com/Need-help-understanding-vacuum-verbose-output-tp2265895p2266912.html

I am framing the question here in relation to pgstattuple.  Running 8.4.4 on
Centos.

I have a table T with 5,063,463 rows.   It was just restored from a backup,
and there is no other activity in this database.  I ran a vacuum.

pg_stat_user_tables.n_dead_tup (which is really
pg_stat_get_dead_tuples('T'::regclass::oid)) says 0
pgstattuple says dead_tuple_count=0, free_space=1,355,152

1. I delete 10,000 rows.

pg_stat_user_tables.n_live_tup -> 5053463
pg_stat_user_tables.n_dead_tup -> 1
pgstattuple.dead_tuple_count -> 1
pgstattuple.free_space -> 1355152

So far, so good. pgstattuple is counting the dead tuples, and not including
those tuples in the free space count.

2. I delete 15,000 more rows.

pg_stat_user_tables.n_live_tup -> 5038463
pg_stat_user_tables.n_dead_tup -> 25000
pgstattuple.dead_tuple_count -> 15000 ??
pgstattuple.free_space -> 1996904 ??

pgstattuple now appears to count the earlier 10K deleted tuples as no longer
dead, but free space.

3. I delete 50,000 more rows.

pg_stat_user_tables.n_live_tup -> 4988463
pg_stat_user_tables.n_dead_tup -> 75000
pgstattuple.dead_tuple_count -> 50022 ??
pgstattuple.free_space -> 2966628 ??

Same thing, pgstattuple appears to "see" only the most recent delete
transaction (but off by 22), and count the prior ones as free.

4. vacuum verbose

vacuum verbose t;
INFO:  vacuuming "public.t"
INFO:  scanned index "t_pkey" to remove 75000 row versions
DETAIL:  CPU 0.01s/0.38u sec elapsed 0.40 sec.
INFO:  "t": removed 75000 row versions in 637 pages
DETAIL:  CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  index "t_pkey" now contains 4988463 row versions in 13886 pages
DETAIL:  75000 index row versions were removed.
204 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO:  "t": found 50022 removable, 3696 nonremovable row versions in 668 out
of 51958 pages
DETAIL:  0 dead row versions cannot be removed yet.
There were 0 unused item pointers.
0 pages are entirely empty.
CPU 0.01s/0.39u sec elapsed 0.40 sec.
VACUUM
Time: 482.771 ms

It seems relevant that vacuum reports the same incorrect number -- 50022 --
as part of its output.  That makes me think that pgstattuple may be using
similar logic to get its dead tuple count.
I wonder if the key to this is that pgstattuple uses
HeapTupleSatisfiesVisibility() to test for deadness.  If so, why would this
call return apparently false positives?  

I know that pgstattuple is meant to be used for debugging only. I have found
pgstatindex to be very helpful in identifying bloat in my indexes.  
Per Tom in the other thread, I now understand that the "found 50022
removable, 3696 nonremovable" line is referring to the subset of pages
that it scanned looking for dead tuples.

I keep coming back to this, though -- 50,022 seems to be just wrong, or
perhaps simply misleading -- i.e. way too low. 
It's present in the output of vacuum, and the output of pgstattuple.
I'd like to understand what meaning this number has, and, ideally, how I can
use to to detect things like bloat or fragmentation.

Thanks!

-- 
View this message in context: 
http://postgresql.1045698.n5.nabble.com/Surprising-dead-tuple-count-from-pgstattuple-tp2266955p2266955.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers