Re: autovac issue with large number of tables - Mailing list pgsql-hackers

From Fujii Masao
Subject Re: autovac issue with large number of tables
Date
Msg-id 4425d4ef-4ae8-95ce-3fa6-81206ee12e02@oss.nttdata.com
Whole thread Raw
In response to Re: autovac issue with large number of tables  (Kasahara Tatsuhito <kasahara.tatsuhito@gmail.com>)
Responses Re: autovac issue with large number of tables
List pgsql-hackers

On 2020/12/03 11:46, Kasahara Tatsuhito wrote:
> On Wed, Dec 2, 2020 at 7:11 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:
>>
>> On Wed, Dec 2, 2020 at 3:33 PM Fujii Masao <masao.fujii@oss.nttdata.com> wrote:
>>>
>>>
>>>
>>> On 2020/12/02 12:53, Masahiko Sawada wrote:
>>>> On Tue, Dec 1, 2020 at 5:31 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:
>>>>>
>>>>> On Tue, Dec 1, 2020 at 4:32 PM Fujii Masao <masao.fujii@oss.nttdata.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 2020/12/01 16:23, Masahiko Sawada wrote:
>>>>>>> On Tue, Dec 1, 2020 at 1:48 PM Kasahara Tatsuhito
>>>>>>> <kasahara.tatsuhito@gmail.com> wrote:
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On Mon, Nov 30, 2020 at 8:59 PM Fujii Masao <masao.fujii@oss.nttdata.com> wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 2020/11/30 10:43, Masahiko Sawada wrote:
>>>>>>>>>> On Sun, Nov 29, 2020 at 10:34 PM Kasahara Tatsuhito
>>>>>>>>>> <kasahara.tatsuhito@gmail.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi, Thanks for you comments.
>>>>>>>>>>>
>>>>>>>>>>> On Fri, Nov 27, 2020 at 9:51 PM Fujii Masao <masao.fujii@oss.nttdata.com> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On 2020/11/27 18:38, Kasahara Tatsuhito wrote:
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Fri, Nov 27, 2020 at 1:43 AM Fujii Masao <masao.fujii@oss.nttdata.com> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 2020/11/26 10:41, Kasahara Tatsuhito wrote:
>>>>>>>>>>>>>>> On Wed, Nov 25, 2020 at 8:46 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Wed, Nov 25, 2020 at 4:18 PM Kasahara Tatsuhito
>>>>>>>>>>>>>>>> <kasahara.tatsuhito@gmail.com> wrote:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On Wed, Nov 25, 2020 at 2:17 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> On Fri, Sep 4, 2020 at 7:50 PM Kasahara Tatsuhito
>>>>>>>>>>>>>>>>>> <kasahara.tatsuhito@gmail.com> wrote:
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> On Wed, Sep 2, 2020 at 2:10 AM Kasahara Tatsuhito
>>>>>>>>>>>>>>>>>>> <kasahara.tatsuhito@gmail.com> wrote:
>>>>>>>>>>>>>>>>>>>>> I wonder if we could have table_recheck_autovac do two probes of the stats
>>>>>>>>>>>>>>>>>>>>> data.  First probe the existing stats data, and if it shows the table to
>>>>>>>>>>>>>>>>>>>>> be already vacuumed, return immediately.  If not, *then* force a stats
>>>>>>>>>>>>>>>>>>>>> re-read, and check a second time.
>>>>>>>>>>>>>>>>>>>> Does the above mean that the second and subsequent table_recheck_autovac()
>>>>>>>>>>>>>>>>>>>> will be improved to first check using the previous refreshed statistics?
>>>>>>>>>>>>>>>>>>>> I think that certainly works.
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> If that's correct, I'll try to create a patch for the PoC
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> I still don't know how to reproduce Jim's troubles, but I was able to reproduce
>>>>>>>>>>>>>>>>>>> what was probably a very similar problem.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> This problem seems to be more likely to occur in cases where you have
>>>>>>>>>>>>>>>>>>> a large number of tables,
>>>>>>>>>>>>>>>>>>> i.e., a large amount of stats, and many small tables need VACUUM at
>>>>>>>>>>>>>>>>>>> the same time.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> So I followed Tom's advice and created a patch for the PoC.
>>>>>>>>>>>>>>>>>>> This patch will enable a flag in the table_recheck_autovac function to use
>>>>>>>>>>>>>>>>>>> the existing stats next time if VACUUM (or ANALYZE) has already been done
>>>>>>>>>>>>>>>>>>> by another worker on the check after the stats have been updated.
>>>>>>>>>>>>>>>>>>> If the tables continue to require VACUUM after the refresh, then a refresh
>>>>>>>>>>>>>>>>>>> will be required instead of using the existing statistics.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> I did simple test with HEAD and HEAD + this PoC patch.
>>>>>>>>>>>>>>>>>>> The tests were conducted in two cases.
>>>>>>>>>>>>>>>>>>> (I changed few configurations. see attached scripts)
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> 1. Normal VACUUM case
>>>>>>>>>>>>>>>>>>>         - SET autovacuum = off
>>>>>>>>>>>>>>>>>>>         - CREATE tables with 100 rows
>>>>>>>>>>>>>>>>>>>         - DELETE 90 rows for each tables
>>>>>>>>>>>>>>>>>>>         - SET autovacuum = on and restart PostgreSQL
>>>>>>>>>>>>>>>>>>>         - Measure the time it takes for all tables to be VACUUMed
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> 2. Anti wrap round VACUUM case
>>>>>>>>>>>>>>>>>>>         - CREATE brank tables
>>>>>>>>>>>>>>>>>>>         - SELECT all of these tables (for generate stats)
>>>>>>>>>>>>>>>>>>>         - SET autovacuum_freeze_max_age to low values and restart PostgreSQL
>>>>>>>>>>>>>>>>>>>         - Consumes a lot of XIDs by using txid_curent()
>>>>>>>>>>>>>>>>>>>         - Measure the time it takes for all tables to be VACUUMed
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> For each test case, the following results were obtained by changing
>>>>>>>>>>>>>>>>>>> autovacuum_max_workers parameters to 1, 2, 3(def) 5 and 10.
>>>>>>>>>>>>>>>>>>> Also changing num of tables to 1000, 5000, 10000 and 20000.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Due to the poor VM environment (2 VCPU/4 GB), the results are a little unstable,
>>>>>>>>>>>>>>>>>>> but I think it's enough to ask for a trend.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> ===========================================================================
>>>>>>>>>>>>>>>>>>> [1.Normal VACUUM case]
>>>>>>>>>>>>>>>>>>>        tables:1000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 20 sec VS (with patch)  20 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 18 sec VS (with patch)  16 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 18 sec VS (with patch)  16 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 19 sec VS (with patch)  17 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD) 19 sec VS (with patch)  17 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>        tables:5000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 77 sec VS (with patch)  78 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 61 sec VS (with patch)  43 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 38 sec VS (with patch)  38 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 45 sec VS (with patch)  37 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD) 43 sec VS (with patch)  35 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>        tables:10000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 152 sec VS (with patch)  153 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 119 sec VS (with patch)   98 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD)  87 sec VS (with patch)   78 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 100 sec VS (with patch)   66 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD)  97 sec VS (with patch)   56 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>        tables:20000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 338 sec VS (with patch)  339 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 231 sec VS (with patch)  229 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 220 sec VS (with patch)  191 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 234 sec VS (with patch)  147 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD) 320 sec VS (with patch)  113 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> [2.Anti wrap round VACUUM case]
>>>>>>>>>>>>>>>>>>>        tables:1000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 19 sec VS (with patch) 18 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 14 sec VS (with patch) 15 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 14 sec VS (with patch) 14 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 14 sec VS (with patch) 16 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD) 16 sec VS (with patch) 14 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>        tables:5000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 69 sec VS (with patch) 69 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 66 sec VS (with patch) 47 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 59 sec VS (with patch) 37 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 39 sec VS (with patch) 28 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD) 39 sec VS (with patch) 29 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>        tables:10000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 139 sec VS (with patch) 138 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 130 sec VS (with patch)  86 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 120 sec VS (with patch)  68 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD)  96 sec VS (with patch)  41 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD)  90 sec VS (with patch)  39 sec
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>        tables:20000
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 1:   (HEAD) 313 sec VS (with patch) 331 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 2:   (HEAD) 209 sec VS (with patch) 201 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 3:   (HEAD) 227 sec VS (with patch) 141 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 5:   (HEAD) 236 sec VS (with patch)  88 sec
>>>>>>>>>>>>>>>>>>>         autovacuum_max_workers 10:  (HEAD) 309 sec VS (with patch)  74 sec
>>>>>>>>>>>>>>>>>>> ===========================================================================
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> The cases without patch, the scalability of the worker has decreased
>>>>>>>>>>>>>>>>>>> as the number of tables has increased.
>>>>>>>>>>>>>>>>>>> In fact, the more workers there are, the longer it takes to complete
>>>>>>>>>>>>>>>>>>> VACUUM to all tables.
>>>>>>>>>>>>>>>>>>> The cases with patch, it shows good scalability with respect to the
>>>>>>>>>>>>>>>>>>> number of workers.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> It seems a good performance improvement even without the patch of
>>>>>>>>>>>>>>>>>> shared memory based stats collector.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Sounds great!
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Note that perf top results showed that hash_search_with_hash_value,
>>>>>>>>>>>>>>>>>>> hash_seq_search and
>>>>>>>>>>>>>>>>>>> pgstat_read_statsfiles are dominant during VACUUM in all patterns,
>>>>>>>>>>>>>>>>>>> with or without the patch.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Therefore, there is still a need to find ways to optimize the reading
>>>>>>>>>>>>>>>>>>> of large amounts of stats.
>>>>>>>>>>>>>>>>>>> However, this patch is effective in its own right, and since there are
>>>>>>>>>>>>>>>>>>> only a few parts to modify,
>>>>>>>>>>>>>>>>>>> I think it should be able to be applied to current (preferably
>>>>>>>>>>>>>>>>>>> pre-v13) PostgreSQL.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +1
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>>> +       /* We might be better to refresh stats */
>>>>>>>>>>>>>>>>>> +       use_existing_stats = false;
>>>>>>>>>>>>>>>>>>           }
>>>>>>>>>>>>>>>>>> +   else
>>>>>>>>>>>>>>>>>> +   {
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> -   heap_freetuple(classTup);
>>>>>>>>>>>>>>>>>> +       heap_freetuple(classTup);
>>>>>>>>>>>>>>>>>> +       /* The relid has already vacuumed, so we might be better to
>>>>>>>>>>>>>>>>>> use exiting stats */
>>>>>>>>>>>>>>>>>> +       use_existing_stats = true;
>>>>>>>>>>>>>>>>>> +   }
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> With that patch, the autovacuum process refreshes the stats in the
>>>>>>>>>>>>>>>>>> next check if it finds out that the table still needs to be vacuumed.
>>>>>>>>>>>>>>>>>> But I guess it's not necessarily true because the next table might be
>>>>>>>>>>>>>>>>>> vacuumed already. So I think we might want to always use the existing
>>>>>>>>>>>>>>>>>> for the first check. What do you think?
>>>>>>>>>>>>>>>>> Thanks for your comment.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> If we assume the case where some workers vacuum on large tables
>>>>>>>>>>>>>>>>> and a single worker vacuum on small tables, the processing
>>>>>>>>>>>>>>>>> performance of the single worker will be slightly lower if the
>>>>>>>>>>>>>>>>> existing statistics are checked every time.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> In fact, at first I tried to check the existing stats every time,
>>>>>>>>>>>>>>>>> but the performance was slightly worse in cases with a small number of workers.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Do you have this benchmark result?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> (Checking the existing stats is lightweight , but at high frequency,
>>>>>>>>>>>>>>>>>        it affects processing performance.)
>>>>>>>>>>>>>>>>> Therefore, at after refresh statistics, determine whether autovac
>>>>>>>>>>>>>>>>> should use the existing statistics.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Yeah, since the test you used uses a lot of small tables, if there are
>>>>>>>>>>>>>>>> a few workers, checking the existing stats is unlikely to return true
>>>>>>>>>>>>>>>> (no need to vacuum). So the cost of existing stats check ends up being
>>>>>>>>>>>>>>>> overhead. Not sure how slow always checking the existing stats was,
>>>>>>>>>>>>>>>> but given that the shared memory based stats collector patch could
>>>>>>>>>>>>>>>> improve the performance of refreshing stats, it might be better not to
>>>>>>>>>>>>>>>> check the existing stats frequently like the patch does. Anyway, I
>>>>>>>>>>>>>>>> think it’s better to evaluate the performance improvement with other
>>>>>>>>>>>>>>>> cases too.
>>>>>>>>>>>>>>> Yeah, I would like to see how much the performance changes in other cases.
>>>>>>>>>>>>>>> In addition, if the shared-based-stats patch is applied, we won't need to reload
>>>>>>>>>>>>>>> a huge stats file, so we will just have to check the stats on
>>>>>>>>>>>>>>> shared-mem every time.
>>>>>>>>>>>>>>> Perhaps the logic of table_recheck_autovac could be simpler.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> BTW, I found some typos in comments, so attache a  fixed version.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The patch adds some duplicated codes into table_recheck_autovac().
>>>>>>>>>>>>>> It's better to make the common function performing them and make
>>>>>>>>>>>>>> table_recheck_autovac() call that common function, to simplify the code.
>>>>>>>>>>>>> Thanks for your comment.
>>>>>>>>>>>>> Hmm.. I've cut out the duplicate part.
>>>>>>>>>>>>> Attach the patch.
>>>>>>>>>>>>> Could you confirm that it fits your expecting?
>>>>>>>>>>>>
>>>>>>>>>>>> Yes, thanks for updataing the patch! Here are another review comments.
>>>>>>>>>>>>
>>>>>>>>>>>> +       shared = pgstat_fetch_stat_dbentry(InvalidOid);
>>>>>>>>>>>> +       dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId);
>>>>>>>>>>>>
>>>>>>>>>>>> When using the existing stats, ISTM that these are not necessary and
>>>>>>>>>>>> we can reuse "shared" and "dbentry" obtained before. Right?
>>>>>>>>>>> Yeah, but unless autovac_refresh_stats() is called, these functions
>>>>>>>>>>> read the information from the
>>>>>>>>>>> local hash table without re-read the stats file, so the process is very light.
>>>>>>>>>>> Therefore, I think, it is better to keep the current logic to keep the
>>>>>>>>>>> code simple.
>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> +               /* We might be better to refresh stats */
>>>>>>>>>>>> +               use_existing_stats = false;
>>>>>>>>>>>>
>>>>>>>>>>>> I think that we should add more comments about why it's better to
>>>>>>>>>>>> refresh the stats in this case.
>>>>>>>>>>>>
>>>>>>>>>>>> +               /* The relid has already vacuumed, so we might be better to use existing stats */
>>>>>>>>>>>> +               use_existing_stats = true;
>>>>>>>>>>>>
>>>>>>>>>>>> I think that we should add more comments about why it's better to
>>>>>>>>>>>> reuse the stats in this case.
>>>>>>>>>>> I added  comments.
>>>>>>>>>>>
>>>>>>>>>>> Attache the patch.
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Thank you for updating the patch. Here are some small comments on the
>>>>>>>>>> latest (v4) patch.
>>>>>>>>>>
>>>>>>>>>> +    * So if the last time we checked a table that was already vacuumed after
>>>>>>>>>> +    * refres stats, check the current statistics before refreshing it.
>>>>>>>>>> +    */
>>>>>>>>>>
>>>>>>>>>> s/refres/refresh/
>>>>>>>> Thanks! fixed.
>>>>>>>> Attached the patch.
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> -----
>>>>>>>>>> +/* Counter to determine if statistics should be refreshed */
>>>>>>>>>> +static bool use_existing_stats = false;
>>>>>>>>>> +
>>>>>>>>>>
>>>>>>>>>> I think 'use_existing_stats' can be declared within table_recheck_autovac().
>>>>>>>>>>
>>>>>>>>>> -----
>>>>>>>>>> While testing the performance, I realized that the statistics are
>>>>>>>>>> reset every time vacuumed one table, leading to re-reading the stats
>>>>>>>>>> file even if 'use_existing_stats' is true. Please refer that vacuum()
>>>>>>>>>> eventually calls AtEOXact_PgStat() which calls to
>>>>>>>>>> pgstat_clear_snapshot().
>>>>>>>>>
>>>>>>>>> Good catch!
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> I believe that's why the performance of the
>>>>>>>>>> method of always checking the existing stats wasn’t good as expected.
>>>>>>>>>> So if we save the statistics somewhere and use it for rechecking, the
>>>>>>>>>> results of the performance benchmark will differ between these two
>>>>>>>>>> methods.
>>>>>>>> Thanks for you checks.
>>>>>>>> But, if a worker did vacuum(), that means this worker had determined
>>>>>>>> need vacuum in the
>>>>>>>> table_recheck_autovac(). So, use_existing_stats set to false, and next
>>>>>>>> time, refresh stats.
>>>>>>>> Therefore I think the current patch is fine, as we want to avoid
>>>>>>>> unnecessary refreshing of
>>>>>>>> statistics before the actual vacuum(), right?
>>>>>>>
>>>>>>> Yes, you're right.
>>>>>>>
>>>>>>> When I benchmarked the performance of the method of always checking
>>>>>>> existing stats I edited your patch so that it sets use_existing_stats
>>>>>>> = true even if the second check is false (i.g., vacuum is needed).
>>>>>>> And the result I got was worse than expected especially in the case of
>>>>>>> a few autovacuum workers. But it doesn't evaluate the performance of
>>>>>>> that method rightly as the stats snapshot is cleared every time
>>>>>>> vacuum. Given you had similar results, I guess you used a similar way
>>>>>>> when evaluating it, is it right? If so, it’s better to fix this issue
>>>>>>> and see how the performance benchmark results will differ.
>>>>>>>
>>>>>>> For example, the results of the test case with 10000 tables and 1
>>>>>>> autovacuum worker I reported before was:
>>>>>>>
>>>>>>> 10000 tables:
>>>>>>>       autovac_workers 1  : 158s,157s, 290s
>>>>>>>
>>>>>>> But after fixing that issue in the third method (always checking the
>>>>>>> existing stats), the results are:
>>>>>>
>>>>>> Could you tell me how you fixed that issue? You copied the stats to
>>>>>> somewhere as you suggested or skipped pgstat_clear_snapshot() as
>>>>>> I suggested?
>>>>>
>>>>> I used the way you suggested in this quick test; skipped
>>>>> pgstat_clear_snapshot().
>>>>>
>>>>>>
>>>>>> Kasahara-san seems not to like the latter idea because it might
>>>>>> cause bad side effect. So we should use the former idea?
>>>>>
>>>>> Not sure. I'm also concerned about the side effect but I've not checked yet.
>>>>>
>>>>> Since probably there is no big difference between the two ways in
>>>>> terms of performance I'm going to see how the performance benchmark
>>>>> result will change first.
>>>>
>>>> I've tested performance improvement again. From the left the execution
>>>> time of the current HEAD, Kasahara-san's patch, the method of always
>>>> checking the existing stats (using approach suggested by Fujii-san),
>>>> in seconds.
>>>>
>>>> 1000 tables:
>>>>      autovac_workers 1  : 13s, 13s, 13s
>>>>      autovac_workers 2  : 6s, 4s, 4s
>>>>      autovac_workers 3  : 3s, 4s, 3s
>>>>      autovac_workers 5  : 3s, 3s, 2s
>>>>      autovac_workers 10: 2s, 3s, 2s
>>>>
>>>> 5000 tables:
>>>>      autovac_workers 1  : 71s, 71s, 72s
>>>>      autovac_workers 2  : 37s, 32s, 32s
>>>>      autovac_workers 3  : 29s, 26s, 26s
>>>>      autovac_workers 5  : 20s, 19s, 18s
>>>>      autovac_workers 10: 13s, 8s, 8s
>>>>
>>>> 10000 tables:
>>>>      autovac_workers 1  : 158s,157s, 159s
>>>>      autovac_workers 2  : 80s, 53s, 78s
>>>>      autovac_workers 3  : 75s, 67s, 67s
>>>>      autovac_workers 5  : 61s, 42s, 42s
>>>>      autovac_workers 10: 69s, 26s, 25s
>>>>
>>>> 20000 tables:
>>>>      autovac_workers 1  : 379s, 380s, 389s
>>>>      autovac_workers 2  : 236s, 232s, 233s
>>>>      autovac_workers 3  : 222s, 181s, 182s
>>>>      autovac_workers 5  : 212s, 132s, 139s
>>>>      autovac_workers 10: 317s, 91s, 89s
>>>>
>>>> I don't see a big difference between Kasahara-san's patch and the
>>>> method of always checking the existing stats.
>>>
>>> Thanks for doing the benchmark!
>>>
>>> This benchmark result makes me think that we don't need to tweak
>>> AtEOXact_PgStat() and can use Kasahara-san approach.
>>> That's good news :)
>>
>> Yeah, given that all autovaucum workers have the list of tables to
>> vacuum in the same order in most cases, the assumption in
>> Kasahara-san’s patch that if a worker needs to vacuum a table it’s
>> unlikely that it will be able to skip the next table using the current
>> snapshot of stats makes sense to me.
>>
>> One small comment on v6 patch:
>>
>> + /* When we decide to do vacuum or analyze, the existing stats cannot
>> + * be reused in the next cycle because it's cleared at the end of vacuum
>> + * or analyze (by AtEOXact_PgStat()).
>> + */
>> + use_existing_stats = false;
>>
>> I think the comment should start on the second line (i.g., \n is
>> needed after /*).
> Oops, thanks.
> Fixed.

Thanks for updating the patch!

I applied the following cosmetic changes to the patch.
Attached is the updated version of the patch.
Coud you review this version?

- Ran pgindent to fix some warnings that "git diff --check"
   reported on the patch.
- Made the order of arguments consistent between
   recheck_relation_needs_vacanalyze and relation_needs_vacanalyze.
- Renamed the variable use_existing_stats to reuse_stats for simplicity.
- Added more comments.

Barring any objection, I'm thinking to commit this version.

Regards,

-- 
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION

Attachment

pgsql-hackers by date:

Previous
From: Amit Kapila
Date:
Subject: Remove incorrect assertion in reorderbuffer.c.
Next
From: Peter Eisentraut
Date:
Subject: Re: SELECT INTO deprecation