How it works…

VACUUM works in three phases. The first main phase is scanning heap. The heap_blks_scanned columns will increase from 0 up to the value of heap_blks_total:

Pid                | 34399 
datid | 12515
datname | postgres
relid | 16422
phase | scanning heap
heap_blks_total | 32787
heap_blks_scanned | 25207
heap_blks_vacuumed | 0
index_vacuum_count | 0
max_dead_tuples | 9541017
num_dead_tuples | 537600

The number of blocks vacuumed is shown as heap_blks_vacuumed and the resulting rows to be removed are shown as num_dead_tuples. After this we switch to the second phase where we start vacuuming indexes:

Pid                | 34399 
datid | 12515
datname | postgres
relid | 16422
phase | vacuuming indexes
heap_blks_total | 32787
heap_blks_scanned | 32787
heap_blks_vacuumed | 0
index_vacuum_count | 0
max_dead_tuples | 9541017
num_dead_tuples | 999966

Though while this phase is happening the progress data doesn't change until it has vacuumed all of the indexes. This phase can take a long time; more indexes increase the time required. Once indexes are vacuumed, we move onto the third phase where we return to the vacuuming heap:

Pid                | 34399 
datid | 12515
datname | postgres
relid | 16422
phase | vacuuming heap
heap_blks_total | 32787
heap_blks_scanned | 32787
heap_blks_vacuumed | 25051
index_vacuum_count | 1
max_dead_tuples | 9541017
num_dead_tuples | 999966

The value of max_dead_tuples is defined by the setting of maintenance_work_mem: PostgreSQL makes space for the largest meaningful number of entries allowed by that setting. If the num_dead_tuples is higher than max_dead_tuples then we repeat phases two and three until complete, so it's a good idea to set maintenance_work_mem high enough to avoid that.

VACUUM moves through various other fairly short phases. If there are many empty blocks at the end of the table VACUUM will attempt to get an AccessExclusiveLock on the table, and once acquired, it will truncate the end of the table—showing a phase of truncating heap. Truncation does not occur every time, because PostgreSQL will attempt it only if the gain is significant and if there's no conflicting lock; if it does it can often last a long time.

All phases of VACUUM will be slowed down by vacuum_cost_delay, but there's nothing you can do there to speed it up.

If you need to change the settings to speed up a running process then autovacuum will pick up any new default settings when you reload the postgresql.conf file.