eldelto
Created:

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>;