How to get database size accurately in postgresql? - postgresql

We are running on PostgreSQL version 9.1, previously we had over 1Billion rows in one table and has been deleted. However, it looks like the \l+ command still reports inaccurately about the actual database size (it reported 568GB but in reality it's much much less than).
The proof of that 568GB is wrong is that the individual table size tally didn't add up to the number, as you can see, top 20 relations has 4292MB in size, the remaining 985 relations are all well below 10MB. In fact all of them add up to about less than 6GB.
Any idea why PostgreSQL so much bloat? If confirmed, how can I debloat? I am not super familiar with VACUUM, is that what I need to do? If so, how?
Much appreciate it.
pmlex=# \l+
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
-----------------+----------+----------+-------------+-------------+-----------------------+---------+------------+--------------------------------------------
pmlex | pmlex | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 568 GB | pg_default |
pmlex_analytics | pmlex | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 433 MB | pg_default |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 5945 kB | pg_default | default administrative connection database
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +| 5841 kB | pg_default | unmodifiable empty database
| | | | | postgres=CTc/postgres | | |
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +| 5841 kB | pg_default | default template for new databases
| | | | | postgres=CTc/postgres | | |
(5 rows)
pmlex=# SELECT nspname || '.' || relname AS "relation",
pmlex-# pg_size_pretty(pg_relation_size(C.oid)) AS "size"
pmlex-# FROM pg_class C
pmlex-# LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
pmlex-# WHERE nspname NOT IN ('pg_catalog', 'information_schema')
pmlex-# ORDER BY pg_relation_size(C.oid) DESC;
relation | size
-------------------------------------+---------
public.page_page | 1289 MB
public.page_pageimagehistory | 570 MB
pg_toast.pg_toast_158103 | 273 MB
public.celery_taskmeta_task_id_key | 233 MB
public.page_page_unique_hash_uniq | 140 MB
public.page_page_ad_text_id | 136 MB
public.page_page_kn_result_id | 125 MB
public.page_page_seo_term_id | 124 MB
public.page_page_kn_search_id | 124 MB
public.page_page_direct_network_tag | 124 MB
public.page_page_traffic_source_id | 123 MB
public.page_page_active | 123 MB
public.page_page_is_referrer | 123 MB
public.page_page_category_id | 123 MB
public.page_page_host_id | 123 MB
public.page_page_serp_id | 121 MB
public.page_page_domain_id | 120 MB
public.celery_taskmeta_pkey | 106 MB
public.page_pagerenderhistory | 102 MB
public.page_page_campaign_id | 89 MB
...
...
...
pg_toast.pg_toast_4354379 | 0 bytes
(1005 rows)

Your options include:
1). Ensuring autovacuum is enabled and set aggressively.
2). Recreating the table as I mentioned in an earlier comment (create-table-as-select + truncate + reload the original table).
3). Running CLUSTER on the table if you can afford to be locked out of that table (exclusive lock).
4). VACUUM FULL, though CLUSTER is more efficient and recommended.
5). Running a plain VACUUM ANALYZE a few times and leaving the table as-is, to eventually fill the space back up as new data comes in.
6). Dump and reload the table via pg_dump
7). pg_repack (though I haven't used it in production)

it will likely look different if you use pg_total_relation_size instead of pg_relation_size
pg_relation_size doesn't give the total size of the table, see
https://www.postgresql.org/docs/9.5/static/functions-admin.html#FUNCTIONS-ADMIN-DBSIZE

Related

PG_WAL is very big size

I have a Postgres cluster with 3 nodes: ETCD+Patroni+Postgres13.
Now there was a problem of constantly growing pg_wal folder. It now contains 5127 files. After searching the internet, I found an article advising you to pay attention to the following database parameters (their meaning at the time of the case is this):
archive_mode off;
wal_level replica;
max_wal_size 1G;
SELECT * FROM pg_replication_slots;
postgres=# SELECT * FROM pg_replication_slots;
-[ RECORD 1 ]-------+------------
slot_name | db2
plugin |
slot_type | physical
datoid |
database |
temporary | f
active | t
active_pid | 2247228
xmin |
catalog_xmin |
restart_lsn | 2D/D0ADC308
confirmed_flush_lsn |
wal_status | reserved
safe_wal_size |
-[ RECORD 2 ]-------+------------
slot_name | db1
plugin |
slot_type | physical
datoid |
database |
temporary | f
active | t
active_pid | 2247227
xmin |
catalog_xmin |
restart_lsn | 2D/D0ADC308
confirmed_flush_lsn |
wal_status | reserved
safe_wal_size |
All other functionality of the Patroni cluster works (switchover, reinit, replication);
root#srvdb3:~# patronictl -c /etc/patroni/patroni.yml list
+ Cluster: mobile (7173650272103321745) --+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+--------+------------+---------+---------+----+-----------+
| db1 | 10.01.1.01 | Replica | running | 17 | 0 |
| db2 | 10.01.1.02 | Replica | running | 17 | 0 |
| db3 | 10.01.1.03 | Leader | running | 17 | |
+--------+------------+---------+---------+----+-----------+
Patroni patroni-edit:
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters:
checkpoint_timeout: 30
hot_standby: 'on'
max_connections: '1100'
max_replication_slots: 5
max_wal_senders: 5
shared_buffers: 2048MB
wal_keep_segments: 5120
wal_level: replica
use_pg_rewind: true
use_slots: true
retry_timeout: 10
ttl: 100
Help please, what could be the matter?
This is what I see in pg_stat_archiver:
postgres=# select * from pg_stat_archiver;
-[ RECORD 1 ]------+------------------------------
archived_count | 0
last_archived_wal |
last_archived_time |
failed_count | 0
last_failed_wal |
last_failed_time |
stats_reset | 2023-01-06 10:21:45.615312+00
If you have wal_keep_segments set to 5120, it is completely normal if you have 5127 WAL segments in pg_wal, because PostgreSQL will always retain at least 5120 old WAL segments. If that is too many for you, reduce the parameter. If you are using replication slots, the only disadvantage is that you might only be able to pg_rewind soon after a failover.

Postgresql pg_table_size() returning wrong data

Table queried size is not same as on physical layout
and table fsm file is of same size as table file. Ideally It should have been very small comparatively.
Postgresql Engine= 13
OS = centos7
Table file size:
# du -sh 16385_vm
8.0K 16385_vm
# du -sh 16385
24K 16385
# du -sh 16385_fsm
24K 16385_fsm
but when I query table sizes are below:
testing=# select pg_size_pretty(pg_relation_size('test1'));
pg_size_pretty
----------------
24 kB
(1 row)
testing=# select pg_size_pretty(pg_total_relation_size('test1'));
pg_size_pretty
----------------
64 kB
(1 row)
testing=# select pg_size_pretty(pg_table_size('test1'));
pg_size_pretty
----------------
64 kB
(1 row)
testing=# \d+ test1
Table "public.test1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+-------------------+-----------+----------+---------+----------+--------------+-------------
id | integer | | | | plain | |
name | character varying | | | | extended | |
Access method: heap
testing=#
**Free space Map:**
testing=# SELECT * FROM pg_freespace('test1');
blkno | avail
-------+-------
0 | 1088
1 | 1120
2 | 3456
(3 rows)
toast table size is also zero:
testing=# select * from pg_class where oid=16385;
-[ RECORD 1 ]-------+------
oid | 16385
relname | test1
relnamespace | 2200
reltype | 16387
reloftype | 0
relowner | 10
relam | 2
relfilenode | 16385
reltablespace | 0
relpages | 3
reltuples | 17
relallvisible | 3
reltoastrelid | 16388
relhasindex | f
relisshared | f
relpersistence | p
relkind | r
relnatts | 2
relchecks | 0
relhasrules | f
relhastriggers | f
relhassubclass | f
relrowsecurity | f
relforcerowsecurity | f
relispopulated | t
relreplident | d
relispartition | f
relrewrite | 0
relfrozenxid | 487
relminmxid | 1
relacl |
reloptions |
relpartbound |
testing=#
[root#ip-10-15-11-219 16384]# du -sh 16388
0 16388
[root#ip-10-15-11-219 16384]#
Then how come sql query is returning 64 KB table and total relation size instead of 24 KB.
Why table fsm file size is 24 kB which is equal to actual table size of 24 KB?

PostgreSQL insert performance - why would it be so slow?

I've got a PostgreSQL database running inside a docker container on an AWS Linux instance. I've got some telemetry running, uploading records in batches of ten. A Python server inserts these records into the database. The table looks like this:
postgres=# \d raw_journey_data ;
Table "public.raw_journey_data"
Column | Type | Collation | Nullable | Default
--------+-----------------------------+-----------+----------+---------
email | character varying | | |
t | timestamp without time zone | | |
lat | numeric(20,18) | | |
lng | numeric(21,18) | | |
speed | numeric(21,18) | | |
There aren't that many rows in the table; about 36,000 presently. But committing the transactions that insert the data is taking about a minute each time:
postgres=# SELECT pid, age(clock_timestamp(), query_start), usename, query
FROM pg_stat_activity
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%'
ORDER BY query_start desc;
pid | age | usename | query
-----+-----------------+----------+--------
30 | | |
32 | | postgres |
28 | | |
27 | | |
29 | | |
37 | 00:00:11.439313 | postgres | COMMIT
36 | 00:00:11.439565 | postgres | COMMIT
39 | 00:00:36.454011 | postgres | COMMIT
56 | 00:00:36.457828 | postgres | COMMIT
61 | 00:00:56.474446 | postgres | COMMIT
35 | 00:00:56.474647 | postgres | COMMIT
(11 rows)
The load average on the system's CPUs is zero and about half of the 4GB system RAM is available (as shown by free). So what causes the super-slow commits here?
The insertion is being done with SqlAlchemy:
db.session.execute(import_table.insert([
{
"email": current_user.email,
"t": row.t.ToDatetime(),
"lat": row.lat,
"lng": row.lng,
"speed": row.speed
}
for row in data.data
]))
Edit Update with the state column:
postgres=# SELECT pid, age(clock_timestamp(), query_start), usename, state, query
FROM pg_stat_activity
WHERE query NOT ILIKE '%pg_stat_activity%'
ORDER BY query_start desc;
pid | age | usename | state | query
-----+-----------------+----------+-------+--------
32 | | postgres | |
30 | | | |
28 | | | |
27 | | | |
29 | | | |
46 | 00:00:08.390177 | postgres | idle | COMMIT
49 | 00:00:08.390348 | postgres | idle | COMMIT
45 | 00:00:23.35249 | postgres | idle | COMMIT
(8 rows)

Postgres import issues - huge table shows 0 rows

I have an issue with a database import. Basically, I am doing this on a postgres 9.6 (production):
/usr/bin/pg_dump mydb | /bin/gzip | /usr/bin/ssh root#1.2.3.4 "cat > /root/20210130.sql.gz"
And on a remote machine I am importing on Postgres 11 like this:
step 1: import schema from a beta machine with Postgres 11
step 2: import data from that export like this: time zcat 20210130.sql.gz | psql mydb
The issue that I have is that one of the tables has 0 rows even though it uses a lot of disk space.
In the original db:
table_schema | table_name | row_estimate | total | index | toast | table
--------------------+--------------------------+--------------+------------+------------+------------+------------
public | test | 5.2443e+06 | 18 GB | 13 GB | 8192 bytes | 4864 MB
In the new db:
table_schema | table_name | row_estimate | total | index | toast | table
--------------------+--------------------------+--------------+------------+------------+------------+------------
public | test | 0 | 4574 MB | 4574 MB | 8192 bytes | 16 kB
What is going on here? How can I fix it?
I can't import the entire DB again because it needed ~7 hours to do the import.

PostgreSQL: Drop DB which exits with no parameters

I am trying from 3 days to drop the 'test123' DB which is not getting drop. Postgres reply of no such db exists.. i have no idea how it listed like this. and the db with \r
template1=# select * from pg_database;
datname | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit | datlastsysoid | datfrozenxid | dattablespace | datacl
-----------------------+--------+----------+-------------+-------------+---------------+--------------+--------------+---------------+--------------+---------------+-------------------------------------
template1 | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | t | t | -1 | 12035 | 709 | 1663 | {=c/postgres,postgres=CTc/postgres}
template0 | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | t | f | -1 | 12035 | 709 | 1663 | {=c/postgres,postgres=CTc/postgres}
postgres | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | f | t | -1 | 12035 | 709 | 1663 |
PremierSuppliers | 16384 | 6 | en_US.UTF-8 | en_US.UTF-8 | f | t | -1 | 12035 | 709 | 1663 |
\r +| 16384 | 6 | en_US.UTF-8 | en_US.UTF-8 | f | t | -1 | 12035 | 709 | 1663 |
test123 | | | | | | | | | | |
Any workaround solution? to drop \r and test123 . i need to know what is the '+' placed in \r . and how to drop it. just to let you know that i already tried the steps given for similiar issue here but my problem not resolved.
The problematic database name seems to consist of a carriage return (ASCII code 13, shown as \r) followed by a newline (ASCII code 10) followed by the string test123
The sequence of characters 13,10 is the end of line in Windows.
The + sign at the end of the column is added by psql as a visual indication that the column continues on the next line. It's not part of the database name.
You may confirm the exact character codes by issuing:
SELECT encode(datname::bytea,'hex') from pg_database where datname like '%test123';
The expected result would be 0d0a74657374313233 if there are no spaces in addition to the CRLF. (otherwise please update the question with the actual result).
If using psql in Unix with readline capabilities, you may drop the database with this sequence of keystrokes:
DROP DATABASE "Ctrl+VCtrl+MEntertest123";Enter
When hitting Ctrl+VCtrl+M the screen should display ^M
EDIT:
If you can't manage it within psql in interactive mode, as an alternative this should also work from bash, to be launched by the postgres user or the database owner:
echo -e "DROP DATABASE \"\r\ntest123\";" | psql -d template1
The -e option to echo enables the interpretation of backslash escapes.