Thread: new vacuum is slower for small tables

new vacuum is slower for small tables

From
"Pavel Stehule"
Date:
Hello,

I did small tests and I found so for small tables (less 1000 rows)
VACUUM based on visibility maps are slower than old implementation

it is about 5ms X 20ms

Regards
Pavel Stehule


Re: new vacuum is slower for small tables

From
Gregory Stark
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:

> Hello,
>
> I did small tests and I found so for small tables (less 1000 rows)
> VACUUM based on visibility maps are slower than old implementation
>
> it is about 5ms X 20ms

Hm, Presumably this is on a machine where the visibility map is entirely in
cache too. On a busy machine that's stealing a page from other table's cache.

The conservative thing to do would be to avoid creating a visibility map for
tables unless they're large enough that it's incontrovertibly enough of a
gain. Especially since speeding up short-lived vacuums doesn't seem terribly
interesting.

Without index-only scans it probably doesn't make much sense to create the
visibility map until we hit something like 32 pages or so. Vacuum should be
able to handle that many pages so fast that speeding it up seems pointless.

--  Gregory Stark EnterpriseDB          http://www.enterprisedb.com Ask me about EnterpriseDB's 24x7 Postgres support!


Re: new vacuum is slower for small tables

From
Heikki Linnakangas
Date:
Pavel Stehule wrote:
> I did small tests and I found so for small tables (less 1000 rows)
> VACUUM based on visibility maps are slower than old implementation
> 
> it is about 5ms X 20ms

How did you measure that?

I tried to reproduce that here, and indeed it seems to be much slower on 
CVS HEAD than on PG 8.3. I tried to short-circuit the vacuum completely, 
making it a no-op:

diff --git a/src/backend/commands/vacuumlazy.c 
b/src/backend/commands/vacuumlazy
index 475c38a..c31917d 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -275,6 +275,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
        lazy_space_alloc(vacrelstats, nblocks);

+       nblocks = 0;        for (blkno = 0; blkno < nblocks; blkno++)        {                Buffer          buf;

but that made no difference at all; vacuuming a one page table on CVS 
HEAD with that hack is still slower than PG 8.3 without that hack. Which 
suggests that the slowdown is not related to visibility map.

Oprofile suggests that most of the time is actually spent in 
pgstat_vacuum_stat. And more precisely in pstat_collect_oids, which is 
called by pgstat_vacuum_stat.

We added support for tracking call counts and elapsed runtime of 
user-defined functions back in May. That added the code to 
pgstat_vacuum_stat to tell stats collector about deleted functions, 
which involves populating a hash table of all functions in the database. 
It looks like *that's* what's causing the slowdown.

I think we can live with the extra overhead.

--   Heikki Linnakangas  EnterpriseDB   http://www.enterprisedb.com


Re: new vacuum is slower for small tables

From
Alvaro Herrera
Date:
Heikki Linnakangas escribió:

> Oprofile suggests that most of the time is actually spent in  
> pgstat_vacuum_stat. And more precisely in pstat_collect_oids, which is  
> called by pgstat_vacuum_stat.

Hmm, that routine is expensive.  Calling it for every vacuum is not good
:-(  Fortunately, autovacuum calls it only once per worker run rather
than once per table.  That limits the damage.

I wonder if we could do better in pgstat_vacuum_stat; for example,
scanning all of pg_proc is useless most of the time, and then it has to
fill and seq-search a hash table with all the builtins which will never
get dropped.  I wonder if we could use pg_depend instead of pg_proc, and
skip pinned functions, for example.

In the end, it would be better if this function was not called at all
for user-invoked vacuum, and have autovacuum handle it.  However, that
doesn't work for people who disable autovacuum.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.


Re: new vacuum is slower for small tables

From
Tom Lane
Date:
Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:
> Oprofile suggests that most of the time is actually spent in 
> pgstat_vacuum_stat. And more precisely in pstat_collect_oids, which is 
> called by pgstat_vacuum_stat.

> We added support for tracking call counts and elapsed runtime of 
> user-defined functions back in May. That added the code to 
> pgstat_vacuum_stat to tell stats collector about deleted functions, 
> which involves populating a hash table of all functions in the database. 
> It looks like *that's* what's causing the slowdown.

> I think we can live with the extra overhead.

Hmm.  It's unfortunate that someone decided to use the exact same
technology for cleaning pg_proc entries as pg_class/pg_database entries,
when the former table has an order of magnitude more entries, most of
which will certainly never change.

It might help if we ignored INTERNAL-language entries in pg_proc.

Or maybe the whole approach is wrong, since there are likely to be
far fewer active stats records for functions than for tables.  In
particular we should at least try to bypass the pg_proc scan when
there are *no* function stats records.
        regards, tom lane


Re: new vacuum is slower for small tables

From
Tom Lane
Date:
Alvaro Herrera <alvherre@commandprompt.com> writes:
> In the end, it would be better if this function was not called at all
> for user-invoked vacuum, and have autovacuum handle it.  However, that
> doesn't work for people who disable autovacuum.

A possible variant on that is to invoke it only in database-wide
vacuums, ie not when you specify a single target table.
        regards, tom lane


Re: new vacuum is slower for small tables

From
Tom Lane
Date:
I wrote:
> ... In particular we should at least try to bypass the pg_proc scan when
> there are *no* function stats records.

That idea, at least, looks to be trivial to implement; so I'll go do so.
        regards, tom lane


Re: new vacuum is slower for small tables

From
"Pavel Stehule"
Date:
2008/12/8 Heikki Linnakangas <heikki.linnakangas@enterprisedb.com>:
> Pavel Stehule wrote:
>>
>> I did small tests and I found so for small tables (less 1000 rows)
>> VACUUM based on visibility maps are slower than old implementation
>>
>> it is about 5ms X 20ms
>
> How did you measure that?

it's simple test

create table x(a integer,  b integer);
insert into x select i, i from generate_series(1,1000) g(i);

and then vacuum on 8.3.5 and vacuum on current CVS HEAD.

both cases are reading from cache.

>
> I tried to reproduce that here, and indeed it seems to be much slower on CVS
> HEAD than on PG 8.3. I tried to short-circuit the vacuum completely, making
> it a no-op:
>
> diff --git a/src/backend/commands/vacuumlazy.c
> b/src/backend/commands/vacuumlazy
> index 475c38a..c31917d 100644
> --- a/src/backend/commands/vacuumlazy.c
> +++ b/src/backend/commands/vacuumlazy.c
> @@ -275,6 +275,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
>
>        lazy_space_alloc(vacrelstats, nblocks);
>
> +       nblocks = 0;
>        for (blkno = 0; blkno < nblocks; blkno++)
>        {
>                Buffer          buf;
>
> but that made no difference at all; vacuuming a one page table on CVS HEAD
> with that hack is still slower than PG 8.3 without that hack. Which suggests
> that the slowdown is not related to visibility map.
>
> Oprofile suggests that most of the time is actually spent in
> pgstat_vacuum_stat. And more precisely in pstat_collect_oids, which is
> called by pgstat_vacuum_stat.
>
> We added support for tracking call counts and elapsed runtime of
> user-defined functions back in May. That added the code to
> pgstat_vacuum_stat to tell stats collector about deleted functions, which
> involves populating a hash table of all functions in the database. It looks
> like *that's* what's causing the slowdown.
>
> I think we can live with the extra overhead.
>
> --
>  Heikki Linnakangas
>  EnterpriseDB   http://www.enterprisedb.com
>


Re: new vacuum is slower for small tables

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> 2008/12/8 Heikki Linnakangas <heikki.linnakangas@enterprisedb.com>:
>> How did you measure that?

> it's simple test

> create table x(a integer,  b integer);
> insert into x select i, i from generate_series(1,1000) g(i);

> and then vacuum on 8.3.5 and vacuum on current CVS HEAD.

Hmm.  There is something else going on here besides the pg_proc scan.
Even after patching that, the elapsed time for a small-table VACUUM is
typically much longer than in 8.3.  But what's really interesting is
that if you repeat it multiple times in quick succession, HEAD's time
jumps all over the place whereas 8.3 is relatively stable:

regression=# vacuum x;
VACUUM
Time: 61.809 ms
regression=# vacuum x;
VACUUM
Time: 10.743 ms
regression=# vacuum x;
VACUUM
Time: 40.615 ms
regression=# vacuum x;
VACUUM
Time: 10.015 ms
regression=# vacuum x;
VACUUM
Time: 53.364 ms
regression=# vacuum x;
VACUUM
Time: 9.324 ms
regression=# vacuum x;
VACUUM
Time: 43.339 ms
regression=# vacuum x;
VACUUM
Time: 9.336 ms
regression=# vacuum x;
VACUUM
Time: 53.271 ms

8.3's time is consistently between 9 and 12 msec on same box and
same data.  Anyone have an idea what's causing this?
        regards, tom lane


Re: new vacuum is slower for small tables

From
"Pavel Stehule"
Date:
It's strange, when I repeat tests, I get usually times about 10 ms,
but cca cca every 5 test it is about 2ms

postgres=# VACUUM x;
VACUUM
Time: 12,093 ms
postgres=# VACUUM x;
VACUUM
Time: 1,928 ms
postgres=# VACUUM x;
VACUUM
Time: 10,743 ms
postgres=# VACUUM x;
VACUUM
Time: 1,927 ms
postgres=# VACUUM x;
VACUUM
Time: 14,248 ms
postgres=# VACUUM x;
VACUUM
Time: 14,677 ms
postgres=# VACUUM x;
VACUUM
Time: 1,871 ms
postgres=# VACUUM x;
VACUUM
Time: 10,417 ms
postgres=# VACUUM x;
VACUUM
Time: 11,786 ms
postgres=# VACUUM x;
VACUUM
Time: 24,204 ms
postgres=# VACUUM x;
VACUUM
Time: 11,112 ms
postgres=# VACUUM x;
VACUUM
Time: 14,577 ms
postgres=# VACUUM x;
VACUUM
Time: 14,671 ms
postgres=# VACUUM x;
VACUUM
Time: 11,544 ms
postgres=# VACUUM x;
VACUUM
Time: 13,267 ms
postgres=# VACUUM x;
VACUUM
Time: 13,768 ms
postgres=# VACUUM x;
VACUUM
Time: 1,831 ms

Regards
Pavel Stehule

2008/12/8 Tom Lane <tgl@sss.pgh.pa.us>:
> "Pavel Stehule" <pavel.stehule@gmail.com> writes:
>> 2008/12/8 Heikki Linnakangas <heikki.linnakangas@enterprisedb.com>:
>>> How did you measure that?
>
>> it's simple test
>
>> create table x(a integer,  b integer);
>> insert into x select i, i from generate_series(1,1000) g(i);
>
>> and then vacuum on 8.3.5 and vacuum on current CVS HEAD.
>
> Hmm.  There is something else going on here besides the pg_proc scan.
> Even after patching that, the elapsed time for a small-table VACUUM is
> typically much longer than in 8.3.  But what's really interesting is
> that if you repeat it multiple times in quick succession, HEAD's time
> jumps all over the place whereas 8.3 is relatively stable:
>
> regression=# vacuum x;
> VACUUM
> Time: 61.809 ms
> regression=# vacuum x;
> VACUUM
> Time: 10.743 ms
> regression=# vacuum x;
> VACUUM
> Time: 40.615 ms
> regression=# vacuum x;
> VACUUM
> Time: 10.015 ms
> regression=# vacuum x;
> VACUUM
> Time: 53.364 ms
> regression=# vacuum x;
> VACUUM
> Time: 9.324 ms
> regression=# vacuum x;
> VACUUM
> Time: 43.339 ms
> regression=# vacuum x;
> VACUUM
> Time: 9.336 ms
> regression=# vacuum x;
> VACUUM
> Time: 53.271 ms
>
> 8.3's time is consistently between 9 and 12 msec on same box and
> same data.  Anyone have an idea what's causing this?
>
>                        regards, tom lane
>


Re: new vacuum is slower for small tables

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> It's strange, when I repeat tests, I get usually times about 10 ms,
> but cca cca every 5 test it is about 2ms

Hmm.  The theory I'd developed for what I see here is that the "slow"
timings correspond to when the pgstat code decides it needs a new stats
file (and so it has to signal the stats collector and wait for the file
to show up).  The "fast" timings occur if the existing stats file is
considered fresh enough to re-use.  Hence, it's "fast" if you re-execute
the VACUUM within half a second of the previous one, else slow.  I can't
tell if that's the same thing you see or not.

Now that we have the flexibility to allow different levels of stats
stale-ness for different callers, I wonder whether it wouldn't be okay
to let pgstat_vacuum_stat work with quite stale files, eg up to a minute
or so.
        regards, tom lane


Re: new vacuum is slower for small tables

From
Bruce Momjian
Date:
Tom Lane wrote:
> "Pavel Stehule" <pavel.stehule@gmail.com> writes:
> > It's strange, when I repeat tests, I get usually times about 10 ms,
> > but cca cca every 5 test it is about 2ms
> 
> Hmm.  The theory I'd developed for what I see here is that the "slow"
> timings correspond to when the pgstat code decides it needs a new stats
> file (and so it has to signal the stats collector and wait for the file
> to show up).  The "fast" timings occur if the existing stats file is
> considered fresh enough to re-use.  Hence, it's "fast" if you re-execute
> the VACUUM within half a second of the previous one, else slow.  I can't
> tell if that's the same thing you see or not.
> 
> Now that we have the flexibility to allow different levels of stats
> stale-ness for different callers, I wonder whether it wouldn't be okay
> to let pgstat_vacuum_stat work with quite stale files, eg up to a minute
> or so.

Are we doing anything on this?

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +