PostgreSQL Cheat Sheet
This is a continuously evolving page where I collect useful but somewhat infrequently used PostgreSQL commands so I don't have to search the internet every single time I need them.
Basic Operations
-- Insert data from another table.
insert into persons from tmp_persons;
-- Update with data from another table.
update orders set email = p.email from persons p where user_id = p.id;
-- Upsert - insert or update conflicting records.
-- EXCLUDED can be used to reference the new values.
insert into persons from tmp_persons
on conflict(id) update set name = EXCLUDED.name;
-- Delete with joining another table.
delete from persons p using orders o where o.customer_id = p.id;CSV Import/Export
-- Export data from withing ~psql~:
\copy (SELECT * FROM persons) to 'persons.csv' with csv;
-- Import data from a CSV to a given table:
\copy persons from 'persons.csv' with csv;Vacuum
-- Get information about running vacuum jobs:
select * from pg_stat_progress_vacuum;
-- Find tables with the highest transaction IDs:
select c.relnamespace::regnamespace as schema_name, c.relname as table_name,
greatest(age(c.relfrozenxid), age(t.relfrozenxid)) as age,
2^31 - 1000000 - greatest(age(c.relfrozenxid), age(t.relfrozenxid)) as remaining
from pg_class c left join pg_class t on c.reltoastrelid = t.oid
where c.relkind in ('r', 'm') order by remaining;
-- Or this even more extensive query from the Timescale blog:
with overridden_tables as (
select
pc.oid as table_id,
pn.nspname as scheme_name,
pc.relname as table_name,
pc.reloptions as options
from pg_class pc
join pg_namespace pn on pn.oid = pc.relnamespace
where reloptions::text ~ 'autovacuum'
), per_database as (
select
coalesce(nullif(n.nspname || '.', 'public.'), '') || c.relname as relation,
greatest(age(c.relfrozenxid), age(t.relfrozenxid)) as age,
round(
(greatest(age(c.relfrozenxid), age(t.relfrozenxid))::numeric *
100 / (2 * 10^9 - current_setting('vacuum_freeze_min_age')::numeric)::numeric),
2
) as capacity_used,
c.relfrozenxid as rel_relfrozenxid,
t.relfrozenxid as toast_relfrozenxid,
(greatest(age(c.relfrozenxid), age(t.relfrozenxid)) > 1200000000)::int as warning,
case when ot.table_id is not null then true else false end as overridden_settings
from pg_class c
join pg_namespace n on c.relnamespace = n.oid
left join pg_class t ON c.reltoastrelid = t.oid
left join overridden_tables ot on ot.table_id = c.oid
where c.relkind IN ('r', 'm') and not (n.nspname = 'pg_catalog' and c.relname <> 'pg_class')
and n.nspname <> 'information_schema'
order by 3 desc)
SELECT *
FROM per_database;Troubleshooting
Find long-running queries:
SELECT
pid,
user,
pg_stat_activity.query_start,
now() - pg_stat_activity.query_start AS query_time,
query,
state,
wait_event_type,
wait_event
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';Kill a query by PID:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid = <pid>
AND pid != pg_backend_pid();Find latency of queries:
SELECT
pss.userid,
pss.dbid,
pd.datname as db_name,
round((pss.total_exec_time + pss.total_plan_time)::numeric, 2) as total_time,
pss.calls,
round((pss.mean_exec_time+pss.mean_plan_time)::numeric, 2) as mean,
round((100 * (pss.total_exec_time + pss.total_plan_time) / sum((pss.total_exec_time + pss.total_plan_time)::numeric) OVER ())::numeric, 2) as cpu_portion_pctg,
substr(pss.query, 1, 200) short_query
FROM pg_stat_statements pss, pg_database pd
WHERE pd.oid=pss.dbid
ORDER BY (pss.total_exec_time + pss.total_plan_time)
DESC LIMIT 30;Extensions
Check if an extension is installed:
SELECT *
FROM pg_available_extensions
WHERE
name = '<extension-name>' and
installed_version is not null;
If the table is empty, create the extension:Install an extension:
CREATE EXTENSION <extension-name>;