PostgreSQL Guide

The world's most advanced open source relational database

โ— PostgreSQL 18 โ€” Complete Reference
35+Years Active
200+Data Types
ACIDCompliant
PG 18Current Release
๐Ÿ˜

Getting Started

PostgreSQL (also known as Postgres) is a powerful, open source object-relational database system with over 35 years of active development. It has earned a strong reputation for reliability, feature robustness, and performance. PostgreSQL runs on all major operating systems and has been ACID-compliant since 2001.

Core

ACID Compliance

Full atomicity, consistency, isolation, and durability for all transactions.

Feature

MVCC

Multi-Version Concurrency Control enables high concurrency without locking.

Feature

Extensibility

Create custom data types, functions, operators, and index methods.

Feature

SQL Standard

Highly conformant to the SQL standard with powerful extensions.

Installation

bash
# macOS (Homebrew)
brew install postgresql@18
brew services start postgresql@18

# Ubuntu / Debian
sudo apt install -y postgresql postgresql-contrib
sudo systemctl start postgresql

# Windows โ€” download the installer from:
# https://www.postgresql.org/download/windows/

# Verify installation
psql --version
# PostgreSQL 18.x

Create Your First Database

sql
-- Connect as superuser
psql -U postgres

-- Create a database
CREATE DATABASE myapp_db;

-- Create a user with password
CREATE USER myapp_user WITH ENCRYPTED PASSWORD 'securepassword';

-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE myapp_db TO myapp_user;

-- Connect to the database
\c myapp_db
๐Ÿ’กUse \l to list databases, \dt to list tables, and \d tablename to describe a table in the psql shell.
๐Ÿ“ฆ

Data Types

PostgreSQL supports a rich set of native data types. Choosing the right type improves performance and data integrity.

Type SQL Name Storage Description
integer INT4 4 bytes Signed 4-byte integer (-2B to 2B)
bigint INT8 8 bytes Signed 8-byte integer (ยฑ9.2 quintillion)
numeric DECIMAL variable Exact, user-specified precision โ€” ideal for money
double precision FLOAT8 8 bytes IEEE 754 double-precision floating point
serial SERIAL4 4 bytes Auto-incrementing integer (use GENERATED IDENTITY in PG10+)
text TEXT variable Variable-length character string, unlimited
varchar(n) CHARACTER VARYING variable Variable-length string with limit
boolean BOOL 1 byte Logical boolean (TRUE / FALSE)
date DATE 4 bytes Calendar date (year, month, day)
timestamp TIMESTAMP 8 bytes Date and time without timezone
timestamptz TIMESTAMPTZ 8 bytes Date and time with timezone โ€” recommended
uuid UUID 16 bytes Universally unique identifier
jsonb JSONB variable Binary JSON โ€” faster querying, supports indexing
array TYPE[] variable Array of any base type

Array Example

sql
CREATE TABLE products (
  id        SERIAL PRIMARY KEY,
  name      TEXT NOT NULL,
  tags      TEXT[],
  scores    INTEGER[]
);

INSERT INTO products (name, tags, scores) VALUES
  ('Widget A', ARRAY['electronics', 'gadget'], ARRAY[90, 85, 92]);

-- Query with array operators
SELECT * FROM products
WHERE 'electronics' = ANY(tags);

-- Unnest array into rows
SELECT name, unnest(tags) AS tag FROM products;
๐Ÿ†•

PostgreSQL 18 โ€” New Features

PostgreSQL 18 ships with major improvements: uuidv7() for timestamp-ordered UUIDs, virtual generated columns by default, OLD/NEW in RETURNING clauses, skip-scan B-tree indexes, OAuth 2.0 authentication, data checksums enabled by default, and pg_upgrade retaining optimizer statistics.

PG 18

uuidv7()

Time-ordered UUIDs with embedded millisecond timestamps. Far better index locality than random UUIDv4.

PG 18

Virtual Generated Columns

Generated columns now default to VIRTUAL (computed on read, not stored), saving disk space automatically.

PG 18

OLD/NEW in RETURNING

Access both old and new row values in INSERT, UPDATE, DELETE, and MERGE RETURNING clauses.

PG 18

B-tree Skip Scan

Multicolumn indexes can now be used without a leading column condition โ€” more index reuse.

PG 18

OAuth Authentication

Built-in OAuth 2.0 / OIDC support for modern identity provider integrations.

PG 18

Checksums Default On

Data checksums now enabled by default on new clusters. pg_upgrade retains optimizer statistics.

uuidv7() โ€” Time-Ordered UUIDs

sql
-- UUIDv7 embeds millisecond timestamp in high bits (PG 18+)
CREATE TABLE events (
  id         UUID PRIMARY KEY DEFAULT uuidv7(),
  event_type TEXT NOT NULL,
  payload    JSONB
);
-- UUIDs sort chronologically โ€” excellent B-tree locality
SELECT uuidv7();
SELECT uuid_extract_timestamp(uuidv7());
-- UUIDv4 comparison (random, bad B-tree locality)
SELECT gen_random_uuid();

Generated Columns (Virtual Default)

sql
-- VIRTUAL (PG18 default): computed on read, no extra storage
CREATE TABLE products (
  price      NUMERIC(10,2),
  tax_rate   NUMERIC(4,4) DEFAULT 0.18,
  price_incl NUMERIC(10,2) GENERATED ALWAYS AS (price * (1 + tax_rate)) VIRTUAL
);
-- STORED: persisted to disk, can be directly indexed
CREATE TABLE contacts (
  first_name TEXT, last_name TEXT,
  full_name  TEXT GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED
);
CREATE INDEX ON contacts(full_name);

OLD / NEW in RETURNING

sql
UPDATE products SET price = price * 1.10
WHERE category = 'electronics'
RETURNING OLD.price AS old_price, NEW.price AS new_price, NEW.id;

DELETE FROM orders WHERE status = 'cancelled' RETURNING OLD.*;

MERGE INTO inventory i USING shipment s ON i.sku = s.sku
WHEN MATCHED THEN UPDATE SET qty = i.qty + s.qty
WHEN NOT MATCHED THEN INSERT (sku, qty) VALUES (s.sku, s.qty)
RETURNING merge_action(), NEW.sku, NEW.qty;

B-tree Skip Scan

sql
CREATE INDEX idx_dept_salary ON employees(department, salary);
-- PG 18 skip scan: uses index even WITHOUT condition on 'department'
SELECT * FROM employees WHERE salary > 100000;
SET enable_skipscan = on;   -- default in PG 18
SET enable_skipscan = off;  -- disable for testing
๐Ÿ”

Queries

SELECT Fundamentals

sql
SELECT first_name, last_name, email,
  EXTRACT(YEAR FROM created_at) AS signup_year
FROM users
WHERE active = TRUE AND created_at >= '2023-01-01'
ORDER BY last_name ASC, first_name ASC
LIMIT 20 OFFSET 0;

JOINs

sql
-- INNER JOIN
SELECT o.id, u.email, o.total FROM orders o
INNER JOIN users u ON o.user_id = u.id;

-- LEFT JOIN
SELECT u.email, COUNT(o.id) AS order_count
FROM users u LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.email;

-- FULL OUTER JOIN with COALESCE
SELECT COALESCE(a.name, b.name) AS name,
  a.value AS left_val, b.value AS right_val
FROM table_a a FULL OUTER JOIN table_b b ON a.id = b.id;

Common Table Expressions (CTEs)

sql
-- Recursive CTE
WITH RECURSIVE seq(n) AS (
  SELECT 1
  UNION ALL
  SELECT n + 1 FROM seq WHERE n < 10
) SELECT * FROM seq;

-- Multi-step CTE pipeline
WITH
  active_users AS (SELECT id, email FROM users WHERE active = TRUE),
  top_spenders AS (
    SELECT user_id, SUM(amount) AS total FROM payments
    GROUP BY user_id HAVING SUM(amount) > 1000)
SELECT au.email, ts.total FROM active_users au
JOIN top_spenders ts ON au.id = ts.user_id ORDER BY ts.total DESC;

Window Functions

sql
SELECT name, department, salary,
  RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank,
  SUM(salary) OVER (PARTITION BY department) AS dept_total,
  LAG(salary, 1) OVER (PARTITION BY department ORDER BY salary) AS prev_salary,
  PERCENT_RANK() OVER (ORDER BY salary) AS pct_rank
FROM employees;
โšก

Built-in Functions

String Functions

Function Example Result
length(s) length('hello') 5
upper(s) upper('hello') HELLO
lower(s) lower('WORLD') world
trim(s) trim(' hi ') hi
substring(s, start, len) substring('abcdef', 2, 3) bcd
concat(s1, s2, ...) concat('foo', 'bar') foobar
replace(s, from, to) replace('abc','b','X') aXc
split_part(s, delim, n) split_part('a,b,c',',',2) b
regexp_match(s, pattern) regexp_match('foo123', '\d+') {123}
format(fmt, ...) format('Hello %s!', 'World') Hello World!

Math Functions

sql
SELECT
  abs(-42),  ceil(4.2),  floor(4.9),
  round(4.567, 2),  sqrt(144),  power(2, 10),
  mod(17, 5),  random(),  trunc(4.789),
  log(100),  ln(2.71828);
{ }

JSON & JSONB

PostgreSQL has first-class support for JSON data. JSONB stores data in a decomposed binary format that is slightly slower to input but significantly faster to query. JSONB also supports GIN indexing.

sql
CREATE TABLE events (
  id      BIGSERIAL PRIMARY KEY,
  payload JSONB NOT NULL
);
INSERT INTO events (payload) VALUES
  ('{"type":"click","user":{"id":42,"name":"Alice"},"ts":1700000000}');

-- Operators: -> returns JSON, ->> returns text
SELECT
  payload ->> 'type' AS event_type,
  payload -> 'user' ->> 'name' AS user_name,
  (payload ->> 'ts')::BIGINT AS timestamp
FROM events;

-- Containment operator @>
SELECT * FROM events
WHERE payload @> '{"user":{"id":42}}';

-- GIN index for fast JSONB querying
CREATE INDEX idx_events_payload ON events USING gin(payload);
Operator

-> and ->>

-> returns JSON child; ->> returns text.

Operator

@> Containment

Tests whether left JSONB contains right JSONB. Works with GIN indexes.

Function

jsonb_path_query

SQL/JSON path language: jsonb_path_query(doc, '$.users[*].name')

โšก

Indexes

Indexes are critical for query performance. PostgreSQL supports multiple index types, each optimized for different workloads.

Default

B-Tree

Best for equality and range queries. Works on any sortable type.

Full Text

GIN

Generalized Inverted Index. Ideal for arrays, JSONB, and full-text search.

Geometry

GiST

Generalized Search Tree. Used for geometric data and nearest-neighbor searches.

Bloom

BRIN

Block Range INdex. Very small footprint for naturally ordered large tables.

sql
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at DESC);
CREATE INDEX idx_active_users ON users(email) WHERE active = TRUE;
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
CREATE INDEX idx_lower_email ON users(lower(email));
CREATE INDEX idx_fts ON articles USING gin(
  to_tsvector('english', title || ' ' || body));
REINDEX INDEX CONCURRENTLY idx_users_email;
โš ๏ธUse EXPLAIN ANALYZE to verify an index is actually being used. Too many indexes can slow down INSERT/UPDATE/DELETE operations.
๐Ÿ—๏ธ

Data Definition (DDL)

Tables โ€” CREATE, ALTER, DROP

sql
CREATE TABLE orders (
  id         BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  user_id    INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  status     TEXT NOT NULL DEFAULT 'pending',
  total      NUMERIC(12,2) CHECK (total >= 0),
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
ALTER TABLE orders ADD COLUMN notes TEXT;
ALTER TABLE orders RENAME COLUMN notes TO memo;
ALTER TABLE orders DROP COLUMN memo;
DROP TABLE customer_orders CASCADE;
TRUNCATE TABLE orders RESTART IDENTITY CASCADE;

Row-Level Security (RLS)

sql
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY doc_owner ON documents
  USING (owner_id = current_user_id());
CREATE POLICY admin_all ON documents
  TO admin_role USING (TRUE);
โœ๏ธ

Data Manipulation (DML)

INSERT / UPDATE / DELETE

sql
INSERT INTO products (name, price) VALUES
  ('Widget A', 9.99), ('Widget B', 14.99);
INSERT INTO users (email) VALUES ('alice@example.com') RETURNING id, created_at;

UPDATE products SET price = price * 1.10 WHERE category = 'electronics';
DELETE FROM sessions WHERE expires_at < now();

UPSERT & MERGE

sql
-- UPSERT
INSERT INTO product_counts (product_id, count) VALUES (42, 1)
ON CONFLICT (product_id) DO UPDATE SET
  count = product_counts.count + EXCLUDED.count;

-- MERGE (PG 15+)
MERGE INTO customer_accounts ca
USING new_transactions nt ON ca.account_id = nt.account_id
WHEN MATCHED THEN UPDATE SET balance = ca.balance + nt.amount
WHEN NOT MATCHED THEN INSERT (account_id, balance) VALUES (nt.account_id, nt.amount);

-- COPY bulk load
COPY products (name, price) FROM '/tmp/products.csv'
  WITH (FORMAT csv, HEADER true);
๐Ÿ“œ

PL/pgSQL โ€” Stored Functions & Procedures

PL/pgSQL is PostgreSQL's built-in procedural language. Functions return values and can appear in queries. Procedures (called with CALL) can manage their own transactions.

sql
CREATE OR REPLACE FUNCTION calc_tax(price NUMERIC, rate NUMERIC DEFAULT 0.18)
RETURNS NUMERIC AS $$
BEGIN
  RETURN price * (1 + rate);
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- Set-returning function
CREATE OR REPLACE FUNCTION active_orders(uid INT)
RETURNS TABLE(order_id INT, total NUMERIC, status TEXT) AS $$
BEGIN
  RETURN QUERY SELECT id, total, status FROM orders
    WHERE user_id = uid AND status != 'cancelled';
END;
$$ LANGUAGE plpgsql;

Stored Procedures

sql
CREATE OR REPLACE PROCEDURE transfer_funds(
  from_id INT, to_id INT, amount NUMERIC
) LANGUAGE plpgsql AS $$
DECLARE bal NUMERIC;
BEGIN
  SELECT balance INTO bal FROM accounts WHERE id = from_id FOR UPDATE;
  IF bal < amount THEN
    RAISE EXCEPTION 'Insufficient funds';
  END IF;
  UPDATE accounts SET balance = balance - amount WHERE id = from_id;
  UPDATE accounts SET balance = balance + amount WHERE id = to_id;
  COMMIT;
END;
$$;
CALL transfer_funds(101, 202, 500.00);
โšก

Triggers

Triggers automatically execute a function in response to INSERT, UPDATE, DELETE, or TRUNCATE. They fire BEFORE or AFTER the event, at either row or statement level.

sql
-- Auto-set updated_at
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at := now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_updated_at
  BEFORE INSERT OR UPDATE ON users
  FOR EACH ROW EXECUTE FUNCTION set_updated_at();

-- Audit log trigger
CREATE OR REPLACE FUNCTION audit_changes() RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO audit_log(table_name, operation, old_data, new_data)
  VALUES(TG_TABLE_NAME, TG_OP,
    CASE WHEN TG_OP != 'INSERT' THEN row_to_json(OLD) END,
    CASE WHEN TG_OP != 'DELETE' THEN row_to_json(NEW) END);
  RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

-- Conditional trigger
CREATE TRIGGER trg_price_change
  AFTER UPDATE OF price ON products
  FOR EACH ROW WHEN (OLD.price IS DISTINCT FROM NEW.price)
  EXECUTE FUNCTION notify_price_change();
๐Ÿ”’

Concurrency Control

PostgreSQL uses MVCC โ€” each transaction sees a consistent snapshot. Reading never blocks writing and writing never blocks reading.

sql
BEGIN;
  UPDATE accounts SET balance = balance - 100 WHERE id = 1;
  UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

-- Skip locked rows (queue pattern)
SELECT * FROM job_queue WHERE status = 'pending'
ORDER BY created_at LIMIT 1 FOR UPDATE SKIP LOCKED;

-- Advisory locks
SELECT pg_advisory_lock(12345);
SELECT pg_try_advisory_lock(12345);
SELECT pg_advisory_unlock(12345);
Level Dirty Read Non-repeatable Phantom Notes
READ COMMITTED โŒ โœ… โœ… Default level
REPEATABLE READ โŒ โŒ โŒ (PG) Snapshot at txn start
SERIALIZABLE โŒ โŒ โŒ Uses SSI; may raise errors
๐Ÿ—‚๏ธ

Table Partitioning

sql
-- Range partitioning
CREATE TABLE measurement (
  city_id INT, logdate DATE NOT NULL, peaktemp INT
) PARTITION BY RANGE (logdate);

CREATE TABLE m_2024m01 PARTITION OF measurement
  FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');

-- List partitioning
CREATE TABLE orders (id BIGSERIAL, region TEXT, amount NUMERIC)
  PARTITION BY LIST (region);
CREATE TABLE orders_us PARTITION OF orders FOR VALUES IN ('US', 'CA');

-- Hash partitioning
CREATE TABLE users (id BIGSERIAL, email TEXT) PARTITION BY HASH (id);
CREATE TABLE users_p0 PARTITION OF users
  FOR VALUES WITH (MODULUS 4, REMAINDER 0);
๐Ÿ‘๏ธ

Views & Materialized Views

sql
CREATE VIEW active_users AS
  SELECT id, email, name FROM users WHERE active = TRUE;

-- Materialized view (cached results)
CREATE MATERIALIZED VIEW sales_summary AS
  SELECT DATE_TRUNC('month', created_at) AS month,
    SUM(amount) AS total, COUNT(*) AS cnt
  FROM orders GROUP BY 1;

CREATE UNIQUE INDEX ON sales_summary (month);
REFRESH MATERIALIZED VIEW CONCURRENTLY sales_summary;
๐Ÿ”„

Replication & High Availability

PostgreSQL provides two primary types of replication to ensure data redundancy, high availability, and load balancing across multiple servers.

Replication Types

Feature Physical (Streaming) Logical
Granularity Entire Cluster Individual Tables/DBs
Standby State Read-Only (Hot Standby) Read-Write allowed
PG Version Must be same Can be different

1. Physical (Streaming) Replication

This method sends WAL (Write Ahead Log) records from the primary to the standby. The standby is a bit-for-bit exact copy of the primary.

primary: postgresql.conf
-- Enable streaming replication
wal_level = replica
max_wal_senders = 10
hot_standby = on
standby: bash
-- Clone primary to standby data directory
pg_basebackup -h primary_ip -D /var/lib/postgresql/data -U replicator -P -R

2. Logical Replication

Uses a "Publish and Subscribe" model. It allows you to replicate specific tables and even transform data during replication.

publisher (Primary)
CREATE PUBLICATION my_pub FOR TABLE orders, products;
subscriber (Standby)
CREATE SUBSCRIPTION my_sub 
  CONNECTION 'host=primary_ip dbname=mydb user=replicator' 
  PUBLICATION my_pub;

Monitoring Status

sql
-- Check replication lag and status
SELECT * FROM pg_stat_replication;
SELECT * FROM pg_stat_subscription;
๐Ÿ“œ

Write Ahead Log (WAL) & PITR

The Write Ahead Log (WAL) is the backbone of PostgreSQL data integrity. It ensures that no data is lost in the event of a crash by logging changes before they are written to the actual data files.

What is WAL?

When a transaction occurs, Postgres first writes the change to a WAL file in the pg_wal directory. If the server crashes, Postgres replays these logs upon restart to restore the database to a consistent state.

postgresql.conf
wal_level = replica       # Required for archiving/PITR
archive_mode = on         # Enables WAL archiving
archive_command = 'cp %p /mnt/server/archive/%f'

Point-in-Time Recovery (PITR)

PITR allows you to restore your database to a specific moment in the past (e.g., "restore to 10:15 AM yesterday"). This requires a full physical backup plus a continuous stream of WAL archives.

postgresql.conf (Recovery Setup)
restore_command = 'cp /mnt/server/archive/%f %p'
recovery_target_time = '2023-10-27 12:00:00'
recovery_target_action = 'promote'
๐Ÿ’พ

Database Backups

1. Logical Backups (pg_dump)

Creates a script of SQL commands to recreate the database. Best for smaller databases or moving between major versions.

bash
# Backup a single database
pg_dump mydb > backup.sql

# Backup the entire cluster (roles, globals)
pg_dumpall > full_cluster.sql

2. Physical Backups (pg_basebackup)

Creates a bit-for-bit copy of the database files. This is significantly faster for large databases and is the foundation for Replication and PITR.

bash
# Create a physical base backup
pg_basebackup -h localhost -D /path/to/backup -Ft -z -P
๐Ÿงน

Database Maintenance

Maintenance in PostgreSQL is essential for reclaiming space, updating statistics, and preventing transaction ID wraparound. Proper management ensures the database remains fast and healthy over time.

VACUUM: Reclaiming Space

PostgreSQL uses MVCC (Multi-Version Concurrency Control). When a row is deleted or updated, the old version remains on disk as a "dead tuple." VACUUM marks this space as reusable.

sql
-- Standard vacuum: reclaims space for reuse (doesn't lock table)
VACUUM users;

-- Full vacuum: shrinks file on disk (requires ACCESS EXCLUSIVE lock)
VACUUM FULL users;

-- Vacuum with Analyze
VACUUM ANALYZE users;

Autovacuum

The autovacuum daemon automates the execution of VACUUM and ANALYZE commands. It triggers based on the number of inserted, updated, or deleted tuples.

postgresql.conf
autovacuum = on
autovacuum_vacuum_threshold = 50
autovacuum_vacuum_scale_factor = 0.2 -- trigger at 20% bloat
autovacuum_max_workers = 3

ANALYZE & Statistics

The query planner needs accurate statistics to choose the best execution plan. ANALYZE collects data about the distribution of values in each column.

sql
ANALYZE orders;
-- Check when statistics were last gathered
SELECT relname, last_analyze, last_autoanalyze 
FROM pg_stat_user_tables;

Bloat Management

Table or index "bloat" occurs when dead tuples are not reclaimed quickly enough, causing files to grow excessively. Managing bloat is critical for performance.

Monitoring Bloat

Use the pgstattuple extension to find the exact percentage of dead space in a table.

SELECT * FROM pgstattuple('my_table');

Fixing Bloat

If VACUUM FULL is too disruptive, use tools like pg_repack to rebuild tables online without locks.

๐Ÿ“Š

Monitoring

sql
-- Active sessions
SELECT pid, usename, state, now() - query_start AS duration, query
FROM pg_stat_activity WHERE state != 'idle' ORDER BY duration DESC;

-- Top slow queries (pg_stat_statements)
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;

-- Terminate / cancel
SELECT pg_terminate_backend(1234);
SELECT pg_cancel_backend(1234);
View Purpose
pg_stat_activity Live sessions, queries, waits
pg_stat_user_tables Table scans, inserts, dead tuples
pg_stat_user_indexes Index usage frequency
pg_stat_statements Slow query analysis (extension)
pg_locks Current lock holders and waiters
pg_stat_replication Replication lag per standby
๐Ÿ”ง

Administration

Users & Roles

sql
CREATE ROLE read_only;
GRANT CONNECT ON DATABASE mydb TO read_only;
GRANT USAGE ON SCHEMA public TO read_only;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only;
CREATE USER analyst WITH PASSWORD 'pass';
GRANT read_only TO analyst;

Backup & Restore

bash
# Custom compressed format (recommended)
pg_dump -U postgres -Fc mydb > mydb.dump
# Parallel dump for large databases
pg_dump -U postgres -Fd -j 4 -f ./backup_dir mydb
# Restore
pg_restore -U postgres -d mydb mydb.dump

Key Configuration

Parameter Recommended Description
shared_buffers 25% of RAM Memory for caching data pages
effective_cache_size 75% of RAM Hint to planner about OS cache
work_mem 4โ€“64 MB Memory per sort/hash operation
maintenance_work_mem 256 MB โ€“ 1 GB Memory for VACUUM, CREATE INDEX
max_connections 100โ€“300 Use PgBouncer for high concurrency
๐Ÿ”

Authentication & Security

PostgreSQL client authentication is controlled by the pg_hba.conf file. Each record defines who can connect, from where, and using which method.

pg_hba.conf Format

# TYPE  DATABASE   USER           ADDRESS            METHOD
local   all          all                               peer
host    all          all          127.0.0.1/32        scram-sha-256
hostssl all          all          0.0.0.0/0           scram-sha-256
host    postgres     all          192.168.93.0/24     ident

Authentication Methods

Method Description Use Case
trust No password needed Local dev
scram-sha-256 Strong password auth Production
peer OS user matches DB user Unix sockets
oauth OAuth 2.0 (PG18) Cloud SSO
๐Ÿ‘ค

Roles & Privileges

Management Commands

-- Create user with limited privileges
CREATE ROLE app_user WITH LOGIN PASSWORD 'secure!';
-- Grant table access
GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA public TO app_user;
-- Predefined monitoring role
GRANT pg_monitor TO ops_team;
๐Ÿงฉ

Essential Extensions

pg_stat_statements

Track execution statistics for all SQL statements. Essential for performance.

pgvector

Vector similarity search for AI/ML and embeddings.

TimescaleDB

Automatic partitioning and optimization for time-series data.

๐Ÿ‘จโ€๐Ÿ’ผ

The Admin

Ganesh PT

Pudi Tirumala Ganesh

Follow on LinkedIn
PostgreSQL DBA & PL/SQL Developer

"Optimizing data, empowering performance."

Results-driven PostgreSQL DBA & PL/SQL Developer specializing in the design, optimization, and administration of high-performance database environments. I empower organizations by architecting scalable database strategies, significantly reducing query latency, and ensuring continuous data availability through enterprise-grade high-availability solutions.

Core Impact & Expertise:

๐Ÿš€

Reduced query execution time by **40%** for high-traffic e-commerce platforms through advanced tuning.

๐Ÿ›ก๏ธ

Ensured **99.9% uptime** by implementing enterprise-grade replication and disaster recovery strategies.

๐Ÿค–

Automated repetitive workflows using **PL/pgSQL**, saving over 10 manual hours weekly.

๐Ÿ“Š

Achieved **100% data integrity** during massive migrations for government organizations.

๐Ÿ› ๏ธ

Developed complex **Stored Procedures & Triggers** to enforce business logic directly at the database layer.

โš™๏ธ

Architected highly scalable **PL/SQL Packages** and dynamic SQL solutions for flexible data processing.

๐ŸŒ

Resources

Official

PostgreSQL Docs

The official documentation โ€” current and archived versions, comprehensive reference.

Resources

SQL Tips

For more SQL and PL/SQL related topics, visit this site for comprehensive guides.

Tutorial

PostgreSQL Tutorial

postgresqltutorial.com โ€” step-by-step tutorials from beginner to advanced.

Tool

pgAdmin

The most popular open-source administration platform for PostgreSQL.

Tool

pgBouncer

Lightweight connection pooler โ€” essential for high-concurrency production deployments.

Extension

PostGIS

Adds support for geographic objects โ€” the go-to choice for geospatial data.