Optimize and Improve PostgreSQL Performance with VACUUM, ANALYZE, and REINDEX
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
If the application is running on a PostgreSQL database, there are Postgres tasks that can be run to improve and optimize database performance.
Three of these will be introduced in this article: VACUUM, ANALYZE, and REINDEX.
To avoid conflicting database updates or corrupted data, it is recommended to run these commands during a maintenance window and with the application stopped.
In the default PostgreSQL configuration, the AUTOVACUUM daemon is enabled and all required configuration parameters are set as needed.
The daemon will run VACUUM and ANALYZE at regular intervals. If the daemon is enabled, these commands can be run to supplement the daemon's work.
To confirm whether the autovacuum daemon is running on LINUX, use the command below:
$ ps aux|grep autovacuum|grep -v grep
postgres 334 0.0 0.0 2654128 1232 ?? Ss 16Mar17 0:05.63 postgres: autovacuum launcher process
Alternatively, the SQL query below can be used to check the status of the autovacuum in the
SELECT name, setting FROM pg_settings WHERE name ILIKE '%autovacuum%';
The VACUUM command will reclaim storage space occupied by dead tuples.
In normal PostgreSQL operation, tuples that are deleted or obsoleted by an update are not physically removed from their table
VACUUM can be run on its own, or with ANALYZE.
When the option list is surrounded by parentheses, the options can be written in any order. Without parentheses, options must be specified in exactly the order shown below. The parenthesized syntax was added in PostgreSQL 9.0; after which the unparenthesized syntax is deprecated.
In the examples below, [tablename] is optional. Without a table specified, VACUUM will be run on ALL available tables in the current schema that the user has access to.
Plain VACUUM: Frees up space for re-use
Full VACUUM: Locks the database table, and reclaims more space than a plain VACUUM
/* Before Postgres 9.0: */ VACUUM FULL /* Postgres 9.0+: */ VACUUM(FULL) [tablename]
Full VACUUM and ANALYZE: Performs a Full VACUUM and gathers new statistics on query executions paths using ANALYZE
/* Before Postgres 9.0: */ VACUUM FULL ANALYZE [tablename] /* Postgres 9.0+: */ VACUUM(FULL, ANALYZE) [tablename]
Verbose Full VACUUM and ANALYZE: Same as #3, but with verbose progress output
/* Before Postgres 9.0: */ VACUUM FULL VERBOSE ANALYZE [tablename] /* Postgres 9.0+: */ VACUUM(FULL, ANALYZE, VERBOSE) [tablename]
ANALYZE gathers statistics for the query planner to create the most efficient query execution paths. Per PostgreSQL documentation, accurate statistics will help the planner to choose the most appropriate query plan, and thereby improve the speed of query processing.
In the example below, [tablename] is optional. Without a table specified, ANALYZE will be run on available tables in the current schema that the user has access to.
ANALYZE VERBOSE [tablename]
The REINDEX command rebuilds one or more indices, replacing the previous version of the index. REINDEX can be used in many scenarios, including the following (from Postgres documentation):
- An index has become corrupted, and no longer contains valid data. Although in theory, this should never happen, in practice indexes can become corrupted due to software bugs or hardware failures. REINDEX provides a recovery method.
An index has become "bloated", that is it contains many empty or nearly-empty pages. This can occur with B-tree indexes in PostgreSQL under certain uncommon access patterns. REINDEX provides a way to reduce the space consumption of the index by writing a new version of the index without the dead pages.
A storage parameter (such as fillfactor) has been changed for an index, and needs ensure that the change has taken full effect.
An index build with the CONCURRENTLY option failed, leaving an "invalid" index. Such indexes are useless but it can be convenient to use REINDEX to rebuild them. Note that REINDEX will not perform a concurrent build. To build the index without interfering with production it is necessary to drop the index and reissue the CREATE INDEX CONCURRENTLY command.
Any of these can be forced by adding the keyword
FORCE after the command
Recreate a single index, myindex:
REINDEX INDEX myindex
Recreate all indices in a table, mytable:
REINDEX TABLE mytable
Recreate all indices in schema public:
REINDEX SCHEMA public
Recreate all indices in database postgres:
REINDEX DATABASE postgres
Recreate all indices on system catalogs in database postgres:
REINDEX SYSTEM postgres