SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

PostgreSQLAdvanced

Production patterns, performance, security hardening

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore PostgreSQL Team
Expert Content

PostgreSQL — Advanced

Logical Replication

sql
-- Publisher (source database)
-- postgresql.conf: wal_level = logical
ALTER SYSTEM SET wal_level = 'logical';
SELECT pg_reload_conf();

-- Create publication
CREATE PUBLICATION my_pub FOR TABLE users, orders, products;
-- Or for all tables:
CREATE PUBLICATION all_tables FOR ALL TABLES;

-- Subscriber (target database)
CREATE SUBSCRIPTION my_sub
CONNECTION 'postgresql://user:pass@source:5432/mydb'
PUBLICATION my_pub;

-- Check replication status
SELECT * FROM pg_replication_slots;
SELECT * FROM pg_stat_replication;
SELECT * FROM pg_stat_subscription;

-- Use case: zero-downtime migrations
-- 1. Set up logical replication from old to new DB
-- 2. Let it sync
-- 3. Switch app to new DB (< 1 second downtime)
-- 4. Drop replication

Custom Extensions and Functions

sql
-- Stored procedures
CREATE OR REPLACE PROCEDURE transfer_funds(
    from_account_id UUID,
    to_account_id   UUID,
    amount          NUMERIC
)
LANGUAGE plpgsql AS $$
DECLARE
    from_balance NUMERIC;
BEGIN
    -- Lock both accounts (consistent order to prevent deadlocks)
    SELECT balance INTO from_balance
    FROM accounts
    WHERE id = from_account_id
    FOR UPDATE;

    IF from_balance < amount THEN
        RAISE EXCEPTION 'Insufficient funds: % < %', from_balance, amount;
    END IF;

    UPDATE accounts SET balance = balance - amount WHERE id = from_account_id;
    UPDATE accounts SET balance = balance + amount WHERE id = to_account_id;

    INSERT INTO transactions (from_id, to_id, amount, type)
    VALUES (from_account_id, to_account_id, amount, 'transfer');
END;
$$;

-- Call with transaction wrapping
CALL transfer_funds('uuid-1', 'uuid-2', 100.00);

-- Custom aggregate function
CREATE OR REPLACE FUNCTION median_sfunc(state NUMERIC[], val NUMERIC)
RETURNS NUMERIC[] LANGUAGE plpgsql AS $$
BEGIN
    RETURN array_append(state, val);
END;
$$;

CREATE OR REPLACE FUNCTION median_finalfunc(state NUMERIC[])
RETURNS NUMERIC LANGUAGE plpgsql AS $$
DECLARE
    sorted NUMERIC[];
    n INT;
BEGIN
    SELECT array_agg(x ORDER BY x) INTO sorted FROM unnest(state) x;
    n := array_length(sorted, 1);
    IF n = 0 THEN RETURN NULL; END IF;
    IF n % 2 = 1 THEN RETURN sorted[(n+1)/2]; END IF;
    RETURN (sorted[n/2] + sorted[n/2+1]) / 2;
END;
$$;

CREATE AGGREGATE median(NUMERIC) (
    SFUNC = median_sfunc,
    STYPE = NUMERIC[],
    FINALFUNC = median_finalfunc,
    INITCOND = '{}'
);

SELECT department, median(salary), AVG(salary)
FROM employees
GROUP BY department;

TimescaleDB (Time-Series Extension)

sql
-- Install TimescaleDB for metrics, IoT, financial data
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- Convert regular table to hypertable
CREATE TABLE metrics (
    time    TIMESTAMPTZ NOT NULL,
    device  TEXT,
    value   DOUBLE PRECISION,
    tags    JSONB
);
SELECT create_hypertable('metrics', 'time');

-- Auto-compression (reduces storage 90-95%)
SELECT add_compression_policy('metrics', INTERVAL '7 days');

-- Continuous aggregate — pre-computed rollups
CREATE MATERIALIZED VIEW metrics_hourly
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 hour', time) AS hour,
    device,
    AVG(value) AS avg_val,
    MAX(value) AS max_val,
    MIN(value) AS min_val
FROM metrics
GROUP BY hour, device
WITH NO DATA;

SELECT add_continuous_aggregate_policy('metrics_hourly',
    start_offset => INTERVAL '1 month',
    end_offset   => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 hour'
);

-- Query spans automatically use the aggregate when possible
SELECT time_bucket('1 hour', time), AVG(value)
FROM metrics
WHERE time > NOW() - INTERVAL '7 days'
GROUP BY 1 ORDER BY 1;
Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Quick Check — PostgreSQL
1 / 1

What is the first step when optimizing a production system?

Up Next
🗺️
PostgreSQLRoadmap
Step-by-step structured learning path from zero to expert
Also Worth Exploring
← Back to all PostgreSQL modules
IntermediateRoadmap