PostgreSQL

PostgreSQL New Feature - 17 Release (3)

2026.02.19 · Platform Technology Research Team

Read the original in Korean
PostgreSQL New Feature - 17 Release (3)

PostgreSQL New Feature - 17 Release (3)

Author
Platform Technology Research Team
Date
Feb 19, 2026
Description
PostgreSQL 17 Vacuum performance improvements, tested against PostgreSQL 16 for elapsed time, WAL volume, and memory usage.
KO slug
PostgreSQL-NewFeature-6
Series
PostgreSQL
Status
Published
Translation
AI draft
PostgreSQL New Feature is a series:
  1. PostgreSQL 17 key features, parameters, and system catalog changes
  1. PostgreSQL 17 new and improved features
  1. PostgreSQL 17 Vacuum performance improvements
  1. PostgreSQL 17 Incremental Backup
This document covers the Vacuum performance improvements in PostgreSQL 17.
 

Vacuum Performance Improvements

Up to PostgreSQL 16, for implementation reasons, Vacuum could use at most 1GB of memory even if maintenance_work_mem or autovacuum_work_mem was set higher. As a result, the memory area for tracking dead tuples to process could run out, sometimes causing unnecessary table rescans. Also, the data structure that stored found dead tuples was a simple array, which was not efficient when there were many dead tuples.
PostgreSQL 17 changes the Vacuum implementation, including fixes for these problems.
  • To make Vacuum more efficient, a Radix Tree structure was introduced, which can cut memory usage by up to 20x compared to before, and the limit on memory available to Vacuum was removed. Vacuum is also faster when processing large volumes of data.
  • Dead tuple cleanup and tuple freezing are now handled in one pass, which reduces WAL volume, and Vacuum on tables without indexes is more efficient, which also reduces WAL volume.
 

Vacuum Performance Test

We compare Vacuum performance between PostgreSQL 16.4 and PostgreSQL 17.2 in the same environment. Only the autovacuum and maintenance_work_mem parameters are changed for the test; all other parameters use their defaults.
The test has 6 cases in total: after creating 100 million rows, we UPDATE 5%, 50%, or 95% of the data, with and without an index. After each UPDATE, we run the Vacuum command with the VERBOSE option to check Vacuum elapsed time and WAL volume, and check memory usage at the OS level. We also check the case where Vacuum memory usage peaks, using 500 million rows.
📢 To check memory usage during Vacuum, we read smaps every 3 seconds using the PID of the session running Vacuum, and use the highest value observed while Vacuum was running.
📢 VACUUM VERBOSE also prints elapsed time and WAL volume for the TOAST table. In this test, no data is long enough to be stored in a TOAST table, so we don't cover TOAST.
 
 

Vacuum Performance Test Cases

Case
Scenario
Notes
Case 1.
100 million rows + UPDATE 5% of all data
Case 2.
100 million rows + UPDATE 50% of all data
Case 3.
100 million rows + UPDATE 95% of all data
Case 4.
100 million rows + create index + UPDATE 5% of all data
Case 5.
100 million rows + create index + UPDATE 50% of all data
Case 6.
100 million rows + create index + UPDATE 95% of all data
Case 7.
500 million rows + create index + UPDATE 95% of all data
Maximum memory usage during Vacuum
 

Creating Vacuum Performance Test Data

The tests below are run identically on PostgreSQL 16 and PostgreSQL 17.
Tables vacuum_tab01 through vacuum_tab06 get 100 million rows each, and indexes are created on vacuum_tab04 through vacuum_tab06 to compare Vacuum performance with and without an index. In addition, table vacuum_tab10 gets 500 million rows to create a situation where Vacuum uses the maximum amount of memory.
Update the data in the table created for each test case.
Check the Vacuum history of the tables before running Vacuum. Since autovacuum=off and we have not run Vacuum manually, there is no Vacuum history.
To check memory usage during Vacuum, run smaps in a new terminal.
 

Running Vacuum

Run Vacuum for each test case.
The Vacuum results are below. From WAL usage and system usage at the end of the VACUUM VERBOSE output, we check WAL volume and Vacuum elapsed time, and take the highest value from the smaps results collected earlier.
📢 The VACUUM VERBOSE output is explained at the end of this document.
Check the Vacuum history of the tables after running Vacuum. Since Vacuum ran once, vacuum_count=1, and last_vacuum shows the time Vacuum completed.
 

Vacuum Performance Test Results

The Vacuum results on PostgreSQL 16.4 and PostgreSQL 17.2 are shown in the table below.
notion image
  • Shorter elapsed time : Vacuum elapsed time dropped by up to 30%.
  • Lower WAL volume : WAL volume during Vacuum dropped by up to 30%.
  • Lower memory usage : Memory usage during Vacuum dropped by up to 95%.
notion image
The tests confirm the Vacuum performance improvements in PostgreSQL 17, and lower memory usage showed the biggest gain. Memory previously used by Vacuum can now go to other work, which reduces memory contention and is expected to improve workload performance.
📢 full_page_write=on was set during the tests, and changing to full_page_write=off may increase WAL generation.
 
 

Appendix 1. Reading VACUUM VERBOSE

Adding the VERBOSE option when running Vacuum shows the Vacuum process, statistics, and more. The example below explains how to read it.
① Vacuum operation info
  • Vacuum runs on table vacuum_tab04 in the public schema of the postgres database
② Vacuum completion info
  • Vacuum finished on table vacuum_tab04 in the public schema of the postgres database, and the index was scanned once to vacuum the related index
  • index scans: 0 suggests the table has no related index
③ Page statistics
  • 0 removed : 0 pages removed
  • 567570 remain : 567,570 pages remain
  • 567570 scanned (100.00% of total) : 567,570 pages scanned (100% of total)
④ Tuple statistics
  • 5000000 removed : 5,000,000 tuples removed
  • 100000000 remain : 100,000,000 tuples remain
  • 0 are dead but not yet removable : 0 tuples not yet removable
⑤ XID info
  • removable cutoff : XID 780 is the cutoff for removable transactions; at the end of the operation, 0 transactions met the removal condition
  • new relfrozenxid : The new relfrozenxid is 777, 13 transactions ahead of the previous value, which means the range of frozen transaction IDs has expanded
⑥ Frozen Tuple
  • 540,541 pages were frozen (95.24% of total) and 95,000,005 tuples were frozen
⑦ Index statistics
  • 540,540 pages needed an index scan (95.24% of total), and 4,999,995 entries were removed (index entries related to dead tuples cleaned up)
⑧ Index status
  • Shows the status of the vacuum_tab04_idx index
  • 274194 in total : 274,194 pages in total
  • 0 newly deleted : 0 newly deleted pages
  • 0 currently deleted : 0 currently deleted pages
  • 0 reusable : 0 reusable pages
⑨ I/O rate
  • avg read rate: 113.535 MB/s : Average read rate is 113.535 MB/s
  • avg write rate: 113.457 MB/s : Average write rate is 113.457 MB/s
⑩ Buffer usage
  • 567660 hits : 567,660 reads from cache
  • 1382447 misses : 1,382,447 reads from disk
  • 1381488 dirtied : 1,381,488 buffers modified by Vacuum
⑪ WAL statistics
  • 2462415 records : 2,462,415 WAL records written
  • 1354334 full page images : 1,354,334 times full page data was written to WAL (only present when full_page_write=on)
  • 10777301340 bytes : Total WAL size is about 10.78GB
⑫ System resource usage
  • CPU: user: 25.40 s, system: 15.94 s : User CPU time 25.40s, system CPU time 15.94s
  • elapsed: 95.12 s : Vacuum elapsed time 95.12s
 
 

Appendix 2. VACUUM VERBOSE Output for Each Test

PostgreSQL 16.4 VACUUM VERBOSE output
PostgreSQL 17.2 VACUUM VERBOSE output
 
 

 
 
Recommended articles