Using disk space in a PostgreSQL cluster
The following data PostgreSQL is stored on cluster disks:
- temporary files;
- data files;
- transaction logs (WAL);
- logical replication slots;
- DBMS logs;
- system files required for the operation of PostgreSQL.
In Managed Databases, some disk space is reserved for service needs. The total amount of reserved space depends on the version of PostgreSQL.
The reserved portion of the disk space is not available to host databases. Take this into account when selecting a configuration lineup.
You can monitor disk usage using disk full notifications and metrics. For more information about metrics, see Monitoring cluster, nodes, and databases PostgreSQL.
When the amount of used disk space grows, you can check:
If a cluster disk reaches 95% capacity or more, the cluster switches to the DISK_FULL status and becomes read-only. This is necessary to prevent complete locking or corruption of the cluster due to a lack of free space. To make the cluster available for reading and writing, clean up the disk or scale the cluster and select a configuration with a larger disk size than in the previous configuration.
Disk full notifications
Disk full notifications are sent to the email address of the Account Owner and users subscribed to the notification category "Services and Products". Notifications are sent when the disk reaches 80% and 95% capacity.
View temporary file size
Temporary files can be used for sorting, hashing, and temporarily storing query results. To view the total size of temporary files in a database, use an SQL query to the view pg_stat_database:
SELECT datname, temp_files AS "Temporary files", temp_bytes AS "Size of temporary files"
FROM pg_stat_database;
Sample output:
datname | temp_files | temp_bytes
--------+--------------+----------------
mydb | 2 | 16384
postgres| 1 | 8192
Where:
datname— database name;temp_files— number of temporary files in this database;temp_bytes— size of temporary files in bytes.
The temp_files and temp_bytes fields account for all temporary files since the cluster was created. The data is reset only after restoring from a backup or after a crash. Use the values of these fields to track changes in the total size of temporary files.
The size of temporary tables created by a specific query can be obtained using the command EXPLAIN ANALYZE.
Check consumers of logical replication slots
Logical replication slots are used for continuous data replication from one database to another. Logical replication slots must always have a consumer. If there is no consumer, file size will grow.
For more information about managing logical replication slots, see the Subscription article in the PostgreSQL documentation.
To check if logical replication slots have consumers, send an SQL query to the view pg_replication_slots:
SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),restart_lsn)) AS replicationSlotLag,active
FROM pg_replication_slots;
Sample output:
slot_name | replicationslotlag | active
-----------------+--------------------+--------
myslot1 | 129 GB | f
myslot2 | 704 MB | t
myslot3 | 624 MB | t
Where:
slot_name— logical replication slot name;replicationslotlag— size of WAL files that will not be automatically deleted during checkpoints and that consumers of the logical replication slot can use;active— boolean value indicating whether the logical replication slot is in use:f— the slot has no consumer;t— the slot has a consumer.
If you have PostgreSQL version 13 or higher, you can limit the maximum size of stored WAL files using the max_slot_wal_keep_size parameter. Note that when using this parameter, the write-ahead log may be deleted before the consumer reads changes from the logical replication slot.
Dead tuples
When you update rows in a table (UPDATE) or delete them (DELETE), tuples are not actually removed from disk; instead, new versions of them are created. Old versions of tuples are called "dead" (dead tuples). Such versioning is required to implement the MVCC (Multi-Version Concurrency Control) process. Even though rows are modified in one transaction, other active transactions can continue to see the old version of the rows. "Dead" tuples can only be deleted when all active transactions are closed.
Dead tuples will also be created on the replica if you use logical replication.
Check dead tuples
If there are many dead tuples, they can take up a significant amount of disk space. To check the number of dead tuples, you can use the PostgreSQL extension pgstattuple or the view pg_stat_all_tables.
Example SQL query to the view pg_stat_all_tables:
SELECT * FROM pg_stat_all_tables WHERE relname='test';
Sample output:
-[ RECORD 1 ]----------+------------------------------
relid | 16395
schemaname | public
relname | test
seq_scan | 3
seq_tup_read | 5280041
idx_scan |
idx_tup_fetch |
n_tup_ins | 2000000
n_tup_upd | 0
n_tup_del | 3639911
n_tup_hot_upd | 0
n_live_tup | 1635941
n_dead_tup | 1999952
n_mod_since_analyze | 3999952
last_vacuum |
last_autovacuum | 2023-02-16 04:49:52.399546+00
last_analyze | 2023-02-09 09:44:56.208889+00
last_autoanalyze | 2023-02-16 04:50:22.581935+00
vacuum_count | 0
autovacuum_count | 1
analyze_count | 1
autoanalyze_count | 1
Where n_dead_tup is the number of dead tuples.
Comparison of dead tuple removal methods
To delete dead tuples, you can use the standard commands VACUUM, VACUUM FULL, or repack tables and indexes using the pg_repack extension.
For more information about the VACUUM and VACUUM FULL commands, see the Routine Vacuuming article in the PostgreSQL documentation.
For more information about the pg_repack extension and its functions, see the pg_repack documentation.
Repack tables and indexes using pg_repack
Run pg_repack during periods of minimal cluster load, as pg_repack creates additional load. For more information about monitoring the cluster status, see Monitoring cluster, nodes, and databases PostgreSQL.
To work with the pg_repack extension, the client of the same name is used. The client is installed on the host from which you connect to the cluster PostgreSQL.
-
Add the
pg_repackextension to the database. -
Determine the version of the extension
pg_repack:2.1. Connect to the cluster. When connecting, specify the name of the database to which you added the extension
pg_repack.2.2. Determine the extension version:
SELECTextname AS extension,extversion AS version,extnamespace::regnamespace AS schemaFROM pg_extensionWHERE extname = 'pg_repack'; -
Download and install the pg_repack client of the same version as the extension.
-
Make sure there is enough free disk space. A full repack of tables requires free disk space approximately twice the size of the tables and indexes being processed. For example, if the total size of the processed tables and indexes is 1 GB, an additional 2 GB of disk space will be required.
-
Make sure that the table being processed has a primary key (
PRIMARY KEY) or a unique index (UNIQUE INDEX). -
Repack tables and indexes in the database:
pg_repack -k -h <host> -p <port> \-U <user> \-d <database_name> \-t <table_name> \-i <index_name>Specify:
<host>— node DNS address;<port>— connection port;<user>— database username;<database_name>— database name;- optional:
-t <table_name>, where<table_name>is the table name. Use this parameter if you need to repack an individual table. To repack multiple tables, specify the required number of-tparameters — one for each table; - optional:
-i <index_name>, where<index_name>is the index name. Use this parameter if you need to repack an individual index. To repack multiple indexes, specify the required number of-iparameters — one for each index. If the index belongs to a table that you have already specified using the-tparameter, you do not need to specify it separately using the-iparameter — the index will be repacked automatically along with the table.
If you do not specify the
-tand-iparameters,pg_repackwill repack all tables and indexes in the specified database.
Clean up disk
We do not recommend using the DELETE FROM table WHERE ... query to clean up disk space. This query can create large query result sets on large tables and place them on the disk. The remaining free space on the disk can be completely exhausted, leading to issues with PostgreSQL and the need to restore its operation manually.
Open a transaction_read_only = no transaction and delete unneeded data using one of the queries:
-
DROP TABLE— completely deletes the table: data, structure, indexes, constraints (constraints), triggers.BEGIN;SET transaction_read_only = no;DROP TABLE table_name;COMMIT; -
TRUNCATE TABLE— deletes all rows from the table. Works faster thanDELETE.BEGIN;SET transaction_read_only = no;TRUNCATE TABLE table_name;COMMIT; -
DELETE— deletes rows specified in the conditionWHERE.