List Your psql Scripts
Introduction
If you are a PostgreSQL database administrator like me where you operate many databases, it is a vital task to organize your sql-scripts in a way for easy lookup and execution. I have tons of scripts. How am I supposed to have them at hand when I need them? I need to lookup these scripts from within psql to stay focused. I will share with you my solution to this problem.
I need fast answers to all kinds of questions:
- Who is logged in? (w.sql)
- What queries are running? - active sessions (as.sql)
- Bloat, is vacuuming happening?
- Who has ingested the most data? schema size, database size
Setting Up a PostgreSQL Server with Docker Compose
Docker Compose Configuration
First, let’s create a PostgreSQL server to work with:
services:
db:
image: "postgres:latest"
container_name: db
ports:
- 5432:5432
environment:
POSTGRES_USER: "root"
POSTGRES_PASSWORD: "secret"
POSTGRES_DB: "db"
command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all
volumes:
- ./data:/var/lib/postgresql
Starting the Service
Start the container in detached mode:
$ docker compose up -d
Setting Environment Variables
For convenience, create an environment file:
$ cat env.sh
export PGHOST=localhost
export PGUSER=root
export PGPASSWORD=secret
export PGPORT=5432
export PGDATABASE=db
export PGOPTIONS=--search_path=public
Source it before connecting:
$ . env.sh
Using the Script Listing Feature
Now let’s demonstrate how to list and access scripts. First, connect to psql:
$ psql
List Scripts by Name
Use the custom :ls command to filter scripts. For example, to find all scripts containing “size”:
[localhost] root@db =# \set f size
[localhost] root@db =# :ls
/Users/BJBRA/projects/postgesql/psql/tablesize.sql
/Users/BJBRA/projects/postgesql/psql/tuplesize_by_page.sql
/Users/BJBRA/projects/postgesql/psql/dbsize.sql
/Users/BJBRA/projects/postgesql/psql/tablesize1.sql
/Users/BJBRA/projects/postgesql/psql/schemas_by_size.sql
/Users/BJBRA/projects/postgesql/psql/objectsize.sql
/Users/BJBRA/projects/postgesql/psql/tablesize_partitioned.sql
Execute a Script
Now execute one of the scripts to see schema sizes:
[localhost] root@db =# \i /Users/BJBRA/projects/postgesql/psql/schemas_by_size.sql
┌────────────────────┬─────────┐
│ table_schema │ size_mb │
├────────────────────┼─────────┤
│ public │ 760.48 │
│ pg_catalog │ 7.53 │
│ information_schema │ 0.24 │
└────────────────────┴─────────┘
(3 rows)
Or check database sizes:
[localhost] root@db =# \i /Users/BJBRA/projects/postgesql/psql/dbsize.sql
┌───────────────┬────────────┐
│ database_name │ size_in_mb │
├───────────────┼────────────┤
│ db │ 768 MB │
│ template1 │ 7556 kB │
│ postgres │ 7492 kB │
│ template0 │ 7337 kB │
└───────────────┴────────────┘
(4 rows)
How It Works
The magic happens with an alias in your ~/.psqlrc file that points to the ls.sql script:
\set ls '\i ~/projects/postgesql/psql/ls.sql'
The ls.sql Script
Here’s the complete ls.sql script that makes this work:
--------------------------------------------------------------------------------
-- name: ls.sql
-- purpose: filter psql scripts from within the psql client.
-- author: Bjarte Brandt
-- date: 01.11.2022
-- usage: \set f <scriptname>
-- :ls
-- notes:
-- set variable 'f' and thereafter run ':ls'
-- all scripts: '\set f *'
--------------------------------------------------------------------------------
-- set session
\set QUIET yes
-- will turn both header and footer off
\pset tuples_only
\unset QUIET
-- variable concatenation in psql and output to file '_ls.sql'
\set c '\\! find ~/projects/postgesql/psql -maxdepth 1 -type f -name'
\set q '"'
\out _ls.sql
\qecho :c :q*:f*.sql:q
\out
-- now execute the generated '_ls.sql'
\i _ls.sql
-- cleanup
\! /bin/rm _ls.sql
-- restore session
\set QUIET yes
-- will turn both header and footer on
\pset tuples_only
\unset QUIET
Important Notes
- Store all your scripts in a git repo (e.g.,
~/projects/postgesql/psql/) - Adjust the
ls.sqlscript to point thefindcommand to your preferred directory - Use
\set f *to list all scripts
Viewing Script Contents
You can also view script contents from within psql using a :cat command:
[localhost] root@db =# \set c schemas_by_size
[localhost] root@db =# :cat
select
table_schema,
round(sum(pg_total_relation_size(quote_ident(table_schema) || '.' || quote_ident(table_name)))::decimal / 1024 / 1024, 2) as size_mb
from
information_schema.tables
group by
table_schema
order by size_mb desc;
Conclusion
This approach keeps your PostgreSQL management scripts organized and readily accessible without leaving the psql client. By using aliases and clever shell tricks, you can dramatically improve your workflow when managing multiple databases. Enjoy!