Post

PostgreSQL index creation in production systems

PostgreSQL index creation in production systems

Introduction

Managing indexes in a PostgreSQL database, especially in production environments, is crucial for maintaining optimal performance and ensuring data integrity. Indexes can significantly speed up query performance by allowing the database to quickly locate and access the data. However, creating and managing indexes in a live production system requires careful planning to avoid locking issues and performance degradation.

This blog post provides a list of essential SQL queries to monitor and manage the index creation process in PostgreSQL databases. These queries will help database administrators (DBAs) and developers ensure that indexes are created efficiently and without disrupting the normal operations of the database.

Note: The examples provided in this post are for PostgreSQL version 9.2.

The following are some of the SQL queries to monitor the index creation process in the database.

List all indexes of a table in a database

This query lists all the indexes of a specified table in a given schema. It helps you understand what indexes are already present on the table.

1
2
3
4
5
SELECT indexname,
       indexdef
FROM pg_indexes
WHERE schemaname = 'public'
  AND tablename = 'student';

List the indexes that are in an invalid state

This query helps identify indexes that are in an invalid state, which can be useful for troubleshooting. Invalid indexes might not be used by the database for query optimization.

1
2
3
4
5
SELECT relname, pg_index.indisvalid
FROM pg_class,
     pg_index
WHERE pg_index.indisvalid = false
  AND pg_index.indexrelid = pg_class.oid;

Get PID of all the indexes in progress

This query retrieves the process IDs (PIDs) of all index creation operations currently in progress. It helps you monitor ongoing index creation activities.

1
2
3
SELECT pid, query
FROM pg_stat_activity
WHERE query LIKE 'CREATE INDEX%';

Cancel or terminate a query based on the PID

These queries allow you to cancel or terminate a query based on its PID, which can be useful if an index creation process is causing issues. Canceling a query attempts to stop it gracefully, while terminating it forcefully stops the process.

1
2
SELECT pg_cancel_backend(<PID>);
SELECT pg_terminate_backend(<PID>);

List locks acquired by the queries

This query lists the locks acquired by queries, which can help identify locking issues during index creation. It shows which queries are holding locks and for how long.

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT a.datname,
       l.relation::regclass, l.transactionid,
       l.mode,
       l.GRANTED,
       a.usename,
       a.query,
       a.query_start,
       age(now(), a.query_start) AS "age",
       a.pid
FROM pg_stat_activity a
         JOIN pg_locks l ON l.pid = a.pid
WHERE mode = 'ShareUpdateExclusiveLock'
ORDER BY a.query_start LIMIT 10;

Drop an index

This query drops an index if it exists, which can be useful for cleanup or re-creation purposes. Dropping an index can help improve performance if the index is no longer needed.

1
DROP INDEX IF EXISTS public.idx_student_id_name;

Create an index concurrently

Creating an index concurrently allows other operations to continue while the index is being created, reducing lock contention. This is useful in production environments where downtime needs to be minimized.

1
CREATE INDEX CONCURRENTLY idx_student_id_name ON public.student (student_id, name);

Create an index with an exclusive lock

Creating an index with an exclusive lock ensures that no other operations can modify the table while the index is being created, which can be useful for ensuring data consistency. However, it can cause downtime for other operations on the table.

1
CREATE INDEX idx_student_id_name ON public.student (student_id, name);
This post is licensed under CC BY 4.0 by the author.