Thursday, 30 April 2026

 How to Optimize GIN Indexes in PostgreSQL (Practical Guide)

GIN (Generalized Inverted Index) is extremely powerful for JSONB, arrays, and full‑text search, but if used incorrectly, it can become slow, large, and expensive to maintain.

In this article, you will learn:

  • When GIN indexes are slow
  • How to optimize GIN index creation
  • How to reduce GIN index size
  • How to speed up queries using GIN
  • Best practices for real‑world usage

This guide is practical and beginner‑friendly.


What Is a GIN Index Used For?

GIN indexes are best suited for:

  • JSONB fields
  • Array columns (int[], text[])
  • Full‑text search (tsvector)

Example:

SQL

CREATE INDEX idx_users_profile

ON users

USING GIN (profile);

Show more lines

GIN indexes store individual keys and values, not rows.


Why GIN Indexes Can Become Slow

Common reasons:

  • Large JSONB documents
  • Too many indexed keys
  • High write traffic (INSERT/UPDATE)
  • No query filtering
  • Default configuration not optimized

Optimization focuses on reducing index work.


1. Use jsonb_path_ops Instead of Default GIN

By default, GIN indexes index both keys and values, which increases size.

Default (Slower, Larger)

SQL

CREATE INDEX idx_users_profile

ON users

USING GIN (profile);

Show more lines

Optimized (Smaller, Faster)

SQL

CREATE INDEX idx_users_profile_path

ON users

USING GIN (profile jsonb_path_ops);

 

Show more lines

When to Use jsonb_path_ops

  • You only use @> (containment) queries
  • You don’t search deep nested keys separately

Example Query

SQL

SELECT *

FROM users

WHERE profile @> '{"role": "admin"}';

Show more lines

Faster
Smaller index
Not usable for all JSON operators


2. Use Partial GIN Indexes

Index only the rows you actually query.

Bad (Indexes Everything)

SQL

CREATE INDEX idx_events_data

ON events

USING GIN (data);

Show more lines

Optimized (Partial Index)

SQL

CREATE INDEX idx_active_events_data

ON events

USING GIN (data)

WHERE status = 'ACTIVE';

Show more lines

Benefits:

  • Smaller index
  • Faster scans
  • Less maintenance overhead

3. Avoid Indexing Unused JSON Keys

If you don’t search all JSON keys, don’t index the whole column.

Use Expression Index

SQL

CREATE INDEX idx_user_role

ON users

USING GIN ((profile -> 'role'));

Show more lines

Query:

SQL

SELECT *

FROM users

WHERE profile -> 'role' ? 'admin';

Show more lines

Expression‑based indexing reduces index bloat.


4. Use FASTUPDATE Carefully

GIN indexes maintain a pending list for fast writes.

Default Behavior

SQL

FASTUPDATE = on

Show more lines

Pros:

  • Faster inserts Cons:
  • Pending list grows
  • Queries become slower over time

Disable FASTUPDATE (Read‑Heavy Systems)

SQL

CREATE INDEX idx_users_profile

ON users

USING GIN (profile)

WITH (FASTUPDATE = off);

Show more lines

Better for read‑heavy workloads
Slightly slower inserts


5. Regularly VACUUM and REINDEX GIN Indexes

GIN indexes fragment easily due to MVCC.

Vacuum

SQL

VACUUM ANALYZE users;

Show more lines

Reindex (Important)

SQL

REINDEX INDEX idx_users_profile;

Show more lines

Or reindex entire table:

SQL

REINDEX TABLE users;

Show more lines

This:

  • Removes index bloat
  • Improves lookup performance

6. Use EXPLAIN ANALYZE to Confirm GIN Usage

Always verify that PostgreSQL is actually using the GIN index.

SQL

EXPLAIN ANALYZE

SELECT *

FROM users

WHERE profile @> '{"country": "IN"}';

Show more lines

Look for:

  • Bitmap Index Scan using idx_users_profile
  • NOT Seq Scan

If sequential scan appears:

  • Index may be too big
  • Query not selective enough

7. Limit JSON Document Size

GIN indexes scale with:

  • Number of keys
  • Size of JSON structure

Best practices:

  • Avoid deeply nested JSON
  • Avoid storing unused metadata
  • Normalize frequently queried data into columns

Example:

Bad:

JSON

profile: { huge nested structure }

``

Show more lines

Better:

SQL

role TEXT,

country TEXT

Show more lines

Use JSONB for flexible data, not everything.


8. Use tsvector Instead of Raw JSON for Search

For text search, do not use JSONB GIN.

Bad:

SQL

SELECT * FROM posts WHERE data::text ILIKE '%postgres%';

Show more lines

Optimized:

SQL

CREATE INDEX idx_posts_search

ON posts

USING GIN (search_vector);

Show more lines

With:

SQL

to_tsvector('english', content)

Show more lines

This is significantly faster and cleaner.


When NOT to Use GIN Indexes

Avoid GIN when:

  • Data is small
  • Writes are very frequent
  • Queries are not selective
  • You rarely filter by JSON/array content

GIN is powerful but not always the best choice.


GIN Index Optimization Checklist

Use jsonb_path_ops when possible
Use partial indexes
Index only required expressions
Disable FASTUPDATE for read‑heavy systems
Run VACUUM and REINDEX
Verify with EXPLAIN ANALYZE
Keep JSON structures lean


Summary

  • GIN indexes optimize searches on JSONB, arrays, and text
  • Default GIN settings are not always optimal
  • Index size and maintenance cost matter
  • Proper tuning dramatically improves performance

You now know how to properly optimize GIN indexes in PostgreSQL.

 

Wednesday, 29 April 2026

 PostgreSQL Indexing Deep Dive: Types, Usage, and Best Practices

Indexes are one of the most powerful tools for improving PostgreSQL performance.
In this article, we go deeper into indexing concepts, types of indexes, and how to use them effectively in real‑world applications.

In this article, you will learn:

  • What indexing really means
  • How PostgreSQL uses indexes internally
  • Different types of PostgreSQL indexes
  • How to choose the right index
  • Indexing best practices

This guide is suitable for beginners moving to intermediate level.


What Is Indexing in PostgreSQL?

Indexing is the process of creating data structures that allow PostgreSQL to find rows faster.

Without indexes:

  • PostgreSQL scans every row (Sequential Scan)

With indexes:

  • PostgreSQL uses a fast lookup structure
  • Only relevant rows are accessed

Indexes trade write performance and storage for faster reads.


How PostgreSQL Uses Indexes

When a query is executed:

  1. PostgreSQL checks available indexes
  2. The query planner chooses the best plan
  3. An index scan is used if beneficial
  4. Rows are fetched using pointers from the index

Indexes do not guarantee usage — PostgreSQL decides using query statistics.


Common Index Use Cases

Indexes are useful when:

  • Columns are used in WHERE
  • Columns are used in JOIN
  • Columns are used in ORDER BY
  • Columns are used in GROUP BY

Indexes are less useful when:

  • Tables are very small
  • Columns change frequently
  • Queries return most rows

Default Index Type: B‑Tree Index

B‑tree is the default and most common PostgreSQL index.

Supports:

  • =
  • <, >, <=, >=
  • BETWEEN
  • ORDER BY

Example

SQL

CREATE INDEX idx_users_created_at

ON users (created_at);

Show more lines


UNIQUE Index

A UNIQUE index enforces uniqueness and improves lookup speed.

Example

SQL

CREATE UNIQUE INDEX idx_users_email

ON users (email);

Show more lines

Benefits:

  • Prevents duplicate values
  • Fast equality searches

Composite (Multi‑Column) Index

Composite indexes use more than one column.

Example

SQL

CREATE INDEX idx_orders_user_status

ON orders (user_id, status);

Show more lines

Useful for queries like:

SQL

SELECT *

FROM orders

WHERE user_id = 10 AND status = 'COMPLETED';

Show more lines

Important rule:

  • Index column order matters

Partial Index

A partial index indexes only a subset of rows.

Example

SQL

CREATE INDEX idx_active_users

ON users (email)

WHERE is_active = true;

Show more lines

Benefits:

  • Smaller index size
  • Better performance
  • Ideal for filtered queries

Expression Index

Indexes can be created on expressions.

Example

SQL

CREATE INDEX idx_lower_email

ON users (LOWER(email));

Show more lines

Now this query can use the index:

SQL

SELECT *

FROM users

WHERE LOWER(email) = 'ravi@example.com';

Show more lines


GIN Index (Generalized Inverted Index)

GIN indexes are used for:

  • JSONB
  • Arrays
  • Full‑text search

JSONB Example

SQL

CREATE INDEX idx_users_profile

ON users

USING GIN (profile);

 

Show more lines

Useful for searching inside JSON data.


Hash Index

Hash indexes support equality (=) comparisons only.

Example

SQL

CREATE INDEX idx_users_id_hash

ON users USING HASH (id);

Show more lines

Use rarely — B‑tree is usually better and safer.


Indexes and Performance Cost

Indexes improve SELECT speed but slow:

  • INSERT
  • UPDATE
  • DELETE

Every write operation must update indexes.

Balance is important.


Checking Index Usage

Use EXPLAIN ANALYZE to verify index usage.

SQL

EXPLAIN ANALYZE

SELECT *

FROM users

WHERE email = 'ravi@example.com';

Show more lines

Look for:

  • Index Scan
  • Bitmap Index Scan

Avoid:

  • Sequential Scan on large tables

Removing Unused Indexes

Unused indexes:

  • Waste storage
  • Slow down writes

Drop unused indexes carefully:

SQL

DROP INDEX idx_unused_index;

Show more lines

Always measure performance before dropping.


Index Best Practices

  • Index columns used frequently in WHERE clauses
  • Index foreign key columns
  • Avoid indexing low‑selectivity columns
  • Use partial indexes for filtered data
  • Monitor index usage regularly
  • Avoid unnecessary indexes

Indexes should solve specific performance problems.


Summary

  • Indexing improves data retrieval speed
  • PostgreSQL supports many index types
  • B‑tree is the default and most useful
  • Composite and partial indexes provide flexibility
  • GIN indexes excel with JSONB data
  • Indexes must be used wisely

You now have a strong understanding of PostgreSQL indexing.


What’s Next?

Next, we will focus on PostgreSQL Mini Project applying indexing and performance concepts.

Next article:
PostgreSQL Mini Project: Build a User Management System

 

Tuesday, 28 April 2026

 PostgreSQL Performance Tuning Basics for Beginners

As your database grows, queries may become slow if performance is not managed properly.
PostgreSQL performance tuning is the process of optimizing queries, indexes, and database settings to make applications faster and more efficient.

In this article, you will learn:

  • What performance tuning means
  • Why PostgreSQL queries become slow
  • Basic performance tuning techniques
  • How to analyze query performance
  • Best practices for beginners

This guide is written for beginners.


What Is Performance Tuning in PostgreSQL?

Performance tuning means:

  • Making queries run faster
  • Reducing database load
  • Using system resources efficiently

Good performance tuning ensures:

  • Faster response time
  • Better user experience
  • Scalable applications

Why Do PostgreSQL Queries Become Slow?

Common reasons for slow performance:

  • Missing or incorrect indexes
  • Poorly written SQL queries
  • Fetching unnecessary data
  • Large tables without optimization
  • Too many concurrent requests

Understanding the cause is the first step to optimization.


Use EXPLAIN to Analyze Queries

PostgreSQL provides the EXPLAIN command to show how a query is executed.

Example

SQL

EXPLAIN SELECT * FROM users WHERE email = 'ravi@example.com';

Show more lines

This shows:

  • Whether an index is used
  • How many rows are scanned
  • The query execution plan

Use EXPLAIN ANALYZE

EXPLAIN ANALYZE shows the actual execution time.

SQL

EXPLAIN ANALYZE

SELECT * FROM users WHERE email = 'ravi@example.com';

Show more lines

This is one of the most important tools for performance tuning.


Select Only Required Columns

Avoid using SELECT *.

Bad example:

SQL

SELECT * FROM users;

 

Show more lines

Good example:

SQL

SELECT name, email FROM users;

Show more lines

Fetching unnecessary columns slows down queries.


Use Indexes Properly

Indexes significantly improve performance when used correctly.

Index Commonly Filtered Columns

Example:

SQL

CREATE INDEX idx_users_email

ON users (email);

Show more lines

Use indexes on:

  • WHERE conditions
  • JOIN columns
  • FOREIGN KEY columns

Avoid indexing every column.


Use WHERE Clause Efficiently

Always use WHERE to filter rows.

Example:

SQL

SELECT * FROM orders WHERE status = 'COMPLETED';

Show more lines

Without WHERE, PostgreSQL scans the entire table.


Limit the Number of Rows Returned

Use LIMIT when possible.

SQL

SELECT * FROM users ORDER BY created_at DESC

LIMIT 10;

Show more lines

This improves performance, especially for large tables.


Optimize JOINs

Ensure join columns are indexed.

Example:

SQL

SELECT u.name, o.total

FROM users u

JOIN orders o ON u.id = o.user_id;

Show more lines

Index recommendation:

SQL

CREATE INDEX idx_orders_user_id

ON orders (user_id);

Show more lines

Indexes speed up joins significantly.


Use Proper Data Types

Choosing the correct data type improves performance.

Examples:

  • Use INTEGER instead of TEXT for IDs
  • Use TIMESTAMPTZ for timestamps
  • Use NUMERIC only when precision is needed

Smaller data types use less memory.


Avoid Too Many Indexes

Indexes improve read performance but slow down:

  • INSERT
  • UPDATE
  • DELETE

Balance is necessary:

  • Add indexes carefully
  • Remove unused indexes

Vacuum and Analyze Regularly

PostgreSQL uses MVCC, which requires cleanup.

Run VACUUM

SQL

VACUUM;

Show more lines

Run ANALYZE

SQL

ANALYZE;

Show more lines

These commands:

  • Clean dead rows
  • Update query planner statistics
  • Improve performance

Use Transactions Properly

Group multiple operations into transactions.

SQL

BEGIN;

 

INSERT INTO orders (...);

UPDATE inventory (...);

 

COMMIT;

Show more lines

This reduces overhead and improves consistency.


Monitor Slow Queries

Enable logging for slow queries.

Use log_min_duration_statement to log slow queries.

This helps identify:

  • Performance bottlenecks
  • Poorly written queries

Performance Tuning Best Practices

  • Always analyze queries using EXPLAIN
  • Index frequently queried columns
  • Avoid SELECT *
  • Limit result sets
  • Optimize joins
  • Monitor query performance
  • Clean and analyze database regularly

Simple changes can lead to big performance gains.


Summary

  • Performance tuning improves speed and efficiency
  • Use EXPLAIN and EXPLAIN ANALYZE
  • Index wisely
  • Fetch only required data
  • Optimize queries and joins
  • Maintain database regularly

You now understand PostgreSQL performance tuning basics.


What’s Next?

Next, we will build a complete PostgreSQL mini‑project applying everything learned so far.

Next article:
PostgreSQL Mini Project: Build a Simple User Management System

 

Monday, 27 April 2026

 PostgreSQL Triggers Explained with Real‑World Examples

Sometimes you want the database to automatically perform an action when data is inserted, updated, or deleted.
This is where triggers are used in PostgreSQL.

In this article, you will learn:

  • What triggers are
  • Why triggers are useful
  • How triggers work
  • Types of triggers in PostgreSQL
  • How to create triggers with examples

This guide is written for beginners.


What Is a Trigger in PostgreSQL?

A trigger is a database object that:

  • Automatically executes when a specific event occurs
  • Is attached to a table
  • Runs a function when data changes

Triggers respond to events like:

  • INSERT
  • UPDATE
  • DELETE

Triggers help automate logic inside the database.


Why Use Triggers?

Triggers are useful for:

  • Automatically updating data
  • Logging changes
  • Enforcing business rules
  • Auditing data
  • Maintaining derived or calculated values

Triggers reduce manual work and errors.


How PostgreSQL Triggers Work

A trigger has two parts:

  1. A trigger function (written in PL/pgSQL)
  2. A trigger that calls the function

When an event occurs on a table, PostgreSQL:

  • Executes the trigger
  • Calls the trigger function automatically

Trigger Events

Triggers can fire on:

  • INSERT
  • UPDATE
  • DELETE
  • TRUNCATE

Example:

  • After a row is inserted
  • Before a row is updated

Trigger Timing

Triggers can run:

  • BEFORE the event
  • AFTER the event

BEFORE triggers:

  • Modify data before saving

AFTER triggers:

  • Used for logging or auditing

Example Table

SQL

CREATE TABLE users (

id SERIAL PRIMARY KEY,

name TEXT,

email TEXT,

created_at TIMESTAMP

);

Show more lines


Creating a Trigger Function

Trigger functions do not return a value.
They return a special type called TRIGGER.

Example Trigger Function

SQL

CREATE OR REPLACE FUNCTION set_created_at()

RETURNS TRIGGER AS $

BEGIN

NEW.created_at = NOW();

RETURN NEW;

END;

$ LANGUAGE plpgsql;

Show more lines

This function sets the created_at timestamp automatically.


Creating a Trigger

SQL

CREATE TRIGGER users_created_at_trigger

BEFORE INSERT ON users

FOR EACH ROW

EXECUTE FUNCTION set_created_at();

Show more lines

Now, whenever a user is inserted, created_at is set automatically.


Inserting Data to Test Trigger

SQL

INSERT INTO users (name, email)

VALUES ('Ravi', 'ravi@example.com');

Show more lines

The created_at column is filled automatically.


BEFORE vs AFTER Trigger Example

AFTER INSERT Trigger for Logging

Example log table:

SQL

CREATE TABLE user_logs (

id SERIAL PRIMARY KEY,

user_id INTEGER,

action TEXT,

log_time TIMESTAMP

);

Show more lines


Trigger Function

SQL

CREATE OR REPLACE FUNCTION log_user_insert()

RETURNS TRIGGER AS $

BEGIN

INSERT INTO user_logs(user_id, action, log_time)

VALUES (NEW.id, 'INSERT', NOW());

 

RETURN NEW;

END;

$ LANGUAGE plpgsql;

Show more lines


Create Trigger

SQL

CREATE TRIGGER user_insert_log

AFTER INSERT ON users

FOR EACH ROW

EXECUTE FUNCTION log_user_insert();

Show more lines

Whenever a user is inserted, a log entry is created.


Trigger Using UPDATE

Update Trigger Function

SQL

CREATE OR REPLACE FUNCTION log_user_update()

RETURNS TRIGGER AS $

BEGIN

INSERT INTO user_logs(user_id, action, log_time)

VALUES (NEW.id, 'UPDATE', NOW());

 

RETURN NEW;

END;

$ LANGUAGE plpgsql;

Show more lines


Create UPDATE Trigger

SQL

CREATE TRIGGER user_update_log

AFTER UPDATE ON users

FOR EACH ROW

EXECUTE FUNCTION log_user_update();

Show more lines


OLD and NEW Keywords

Inside trigger functions:

  • NEW refers to new row data
  • OLD refers to old row data

Example:

SQL

OLD.email

NEW.email

Show more lines

Useful for comparing changes.


Viewing Triggers on a Table

SQL

\d users

Show more lines

Triggers attached to the table will be listed.


Dropping a Trigger

SQL

DROP TRIGGER trigger_name ON table_name;

Show more lines

Example:

SQL

DROP TRIGGER user_insert_log ON users;

Show more lines


Dropping a Trigger Function

SQL

DROP FUNCTION function_name;

Show more lines

Example:

SQL

DROP FUNCTION set_created_at;

Show more lines


When NOT to Use Triggers

Avoid triggers when:

  • Logic is very complex
  • Debugging becomes difficult
  • Performance is critical
  • Logic can be handled in application code

Triggers should be used carefully.


Best Practices for Triggers

  • Keep trigger logic simple
  • Use triggers for automation, not heavy logic
  • Avoid recursive triggers
  • Document trigger behavior
  • Test triggers thoroughly

Good triggers improve reliability.


Summary

  • Triggers run automatically on data changes
  • Triggers respond to INSERT, UPDATE, DELETE
  • Trigger functions use PL/pgSQL
  • BEFORE triggers modify data
  • AFTER triggers log or audit changes

You now understand PostgreSQL triggers clearly.


What’s Next?

Next, we will learn error handling and exceptions in PL/pgSQL.

Next article:
PostgreSQL Exception Handling Using PL/pgSQL

 

Sunday, 26 April 2026

 PostgreSQL Exception Handling Using PL/pgSQL

Errors can occur while executing SQL statements due to invalid data, violations of constraints, or unexpected conditions.
PostgreSQL provides exception handling in PL/pgSQL to gracefully manage these errors.

In this article, you will learn:

  • What exceptions are
  • Why exception handling is important
  • How exception handling works in PL/pgSQL
  • Common exception examples
  • Best practices for handling errors

This guide is written for beginners.


What Is an Exception in PostgreSQL?

An exception is an error that occurs while executing SQL or PL/pgSQL code.

Examples of errors:

  • Division by zero
  • Duplicate key violation
  • NULL value violation
  • Data type mismatch

Without handling exceptions, PostgreSQL stops execution and throws an error.


Why Is Exception Handling Important?

Exception handling helps:

  • Prevent application crashes
  • Handle invalid data gracefully
  • Maintain database consistency
  • Log and debug errors
  • Roll back transactions when needed

Proper exception handling makes your database logic safe and reliable.


Exception Handling in PL/pgSQL

PostgreSQL uses the EXCEPTION block to handle errors.

Basic structure:

SQL

BEGIN

-- SQL statements

EXCEPTION

WHEN error_condition THEN

-- error handling logic

END;

Show more lines

When an error occurs inside BEGIN, control moves to the EXCEPTION block.


Simple Exception Handling Example

SQL

CREATE OR REPLACE FUNCTION divide_numbers(a INTEGER, b INTEGER)

RETURNS INTEGER AS $

BEGIN

RETURN a / b;

 

EXCEPTION

WHEN division_by_zero THEN

RETURN 0;

END;

$ LANGUAGE plpgsql;

Show more lines

Calling the function:

SQL

SELECT divide_numbers(10, 0);

Show more lines

Instead of failing, the function returns 0.


Handling UNIQUE Constraint Violation

Example table:

SQL

CREATE TABLE users (

id SERIAL PRIMARY KEY,

email TEXT UNIQUE

);

Show more lines


Function with Exception Handling

SQL

CREATE OR REPLACE FUNCTION insert_user(user_email TEXT)

RETURNS TEXT AS $

BEGIN

INSERT INTO users(email)

VALUES (user_email);

 

RETURN 'User inserted successfully';

 

EXCEPTION

WHEN unique_violation THEN

RETURN 'Email already exists';

END;

$ LANGUAGE plpgsql;

Show more lines

This prevents application failure when duplicate data is inserted.


Using WHEN OTHERS

WHEN OTHERS catches any error.

Example:

SQL

CREATE OR REPLACE FUNCTION safe_insert(user_email TEXT)

RETURNS TEXT AS $

BEGIN

INSERT INTO users(email)

VALUES (user_email);

 

RETURN 'Success';

 

EXCEPTION

WHEN OTHERS THEN

RETURN 'An error occurred';

END;

$ LANGUAGE plpgsql;

Show more lines

Use WHEN OTHERS carefully, as it hides specific errors.


Raising Custom Exceptions

You can raise your own errors using RAISE.

Raise an Exception

SQL

RAISE EXCEPTION 'Invalid input value';

Show more lines


Example with Custom Error

SQL

CREATE OR REPLACE FUNCTION check_age(age INTEGER)

RETURNS TEXT AS $

BEGIN

IF age < 0 THEN

RAISE EXCEPTION 'Age cannot be negative';

END IF;

 

RETURN 'Valid age';

END;

$ LANGUAGE plpgsql;

 

Show more lines

Calling this function with invalid input raises an error.


RAISE NOTICE, WARNING, and INFO

You can display messages without stopping execution.

Example:

SQL

RAISE NOTICE 'Processing started';

RAISE WARNING 'This is a warning';

RAISE INFO 'Execution completed';

Show more lines

These are useful for debugging.


Exception Handling in Procedures

Procedures commonly use exception handling with transaction control.

Example:

SQL

CREATE OR REPLACE PROCEDURE safe_transfer()

LANGUAGE plpgsql

AS $

BEGIN

UPDATE accounts SET balance = balance - 100 WHERE id = 1;

UPDATE accounts SET balance = balance + 100 WHERE id = 2;

 

COMMIT;

 

EXCEPTION

WHEN OTHERS THEN

ROLLBACK;

END;

$;

Show more lines

If any error occurs, the transaction is rolled back.


Common PostgreSQL Exception Conditions

Some commonly used exception names:

  • division_by_zero
  • unique_violation
  • not_null_violation
  • foreign_key_violation
  • check_violation

Using specific exceptions is better than using WHEN OTHERS.


Best Practices for Exception Handling

  • Handle only expected errors
  • Use specific exception names
  • Avoid hiding errors with WHEN OTHERS
  • Log or return meaningful messages
  • Use ROLLBACK in procedures when needed

Good error handling improves maintainability.


Summary

  • Exceptions handle runtime errors
  • Use EXCEPTION blocks in PL/pgSQL
  • Catch specific errors when possible
  • Use RAISE for custom errors
  • Exception handling improves reliability

You now understand exception handling in PostgreSQL.


What’s Next?

Next, we will cover PostgreSQL performance tips and query optimization basics.

Next article:
PostgreSQL Performance Tuning Basics for Beginners

 

 PostgreSQL Procedures Explained (Functions vs Procedures)

PostgreSQL supports procedures for executing logic inside the database.
Procedures are similar to functions but are designed for performing actions rather than returning values.

In this article, you will learn:

  • What procedures are in PostgreSQL
  • Why procedures are used
  • How to create and call procedures
  • Difference between functions and procedures
  • When to use procedures

This guide is written for beginners.


What Is a Procedure in PostgreSQL?

A procedure is a stored block of code that:

  • Performs database operations
  • Can execute multiple SQL statements
  • Does not return a value
  • Can manage transactions

Procedures are mainly used for actions, not calculations.


Why Use Procedures?

PostgreSQL procedures are useful for:

  • Complex business logic
  • Bulk data processing
  • Transaction control (COMMIT / ROLLBACK)
  • Administrative and maintenance tasks
  • Reducing application‑side logic

Procedures keep logic close to the data.


Functions vs Procedures (Important Difference)

Feature

Function

Procedure

Returns value

Yes

No

Can be used in SELECT

Yes

No

Transaction control

No

Yes

Called using

SELECT

CALL


Basic Procedure Syntax

SQL

CREATE OR REPLACE PROCEDURE procedure_name(parameters)

LANGUAGE plpgsql

AS $

BEGIN

-- procedure logic

END;

$;

Show more lines


Creating Your First Procedure

Example: Insert a user into a table.

Example Table

SQL

CREATE TABLE users (

id SERIAL PRIMARY KEY,

name TEXT,

email TEXT

);

Show more lines


Create Procedure

SQL

CREATE OR REPLACE PROCEDURE add_user(

user_name TEXT,

user_email TEXT

)

LANGUAGE plpgsql

AS $

BEGIN

INSERT INTO users(name, email)

VALUES (user_name, user_email);

END;

$;

Show more lines


Calling a Procedure

Procedures are called using CALL.

SQL

CALL add_user('Ravi', 'ravi@example.com');

Show more lines

The data is inserted into the users table.


Procedure with Transaction Control

One major advantage of procedures is transaction handling.

SQL

CREATE OR REPLACE PROCEDURE transfer_amount(

from_id INT,

to_id INT,

amount NUMERIC

)

LANGUAGE plpgsql

AS $

BEGIN

UPDATE accounts

SET balance = balance - amount

WHERE id = from_id;

 

UPDATE accounts

SET balance = balance + amount

WHERE id = to_id;

 

COMMIT;

END;

$;

Show more lines

Functions cannot use COMMIT or ROLLBACK, but procedures can.


Procedure with IF Condition

SQL

CREATE OR REPLACE PROCEDURE check_and_insert(

username TEXT

)

LANGUAGE plpgsql

AS $

BEGIN

IF username IS NOT NULL THEN

INSERT INTO users(name)

VALUES (username);

END IF;

END;

$;

Show more lines


Procedure with Exception Handling

SQL

CREATE OR REPLACE PROCEDURE safe_insert(

user_name TEXT

)

LANGUAGE plpgsql

AS $

BEGIN

INSERT INTO users(name)

VALUES (user_name);

 

EXCEPTION

WHEN OTHERS THEN

ROLLBACK;

END;

$;

Show more lines

This prevents partial or broken data insertion.


Dropping a Procedure

SQL

DROP PROCEDURE procedure_name;

Show more lines

Example:

SQL

DROP PROCEDURE add_user;

Show more lines


When to Use Procedures

Use procedures when:

  • You don’t need to return a value
  • You need transaction control
  • You perform multiple database actions
  • You handle batch processing
  • You run administrative tasks

Use functions when:

  • You need a return value
  • You want to use the result in queries

Best Practices for Procedures

  • Use procedures for logic with side effects
  • Keep procedures focused and readable
  • Handle exceptions properly
  • Use meaningful procedure names
  • Avoid heavy business logic when possible

Well‑designed procedures improve reliability.


Summary

  • Procedures perform actions inside PostgreSQL
  • Procedures do not return values
  • Procedures support transaction control
  • CALL is used to execute procedures
  • Procedures are ideal for complex workflows

You now understand PostgreSQL procedures clearly.


What’s Next?

Next, we will learn about triggers in PostgreSQL.

Next article:
PostgreSQL Triggers Explained with Real‑World Examples

 

Multithreading in PostgreSQL Using dblink and FDW (Reality vs Myth) First: The Critical Truth (Must Be Clear) You cannot create true mul...