The Importance of Postgresql Indexes in Your Rails Application

Optimizing database performance is paramount for the effective functioning of Ruby on Rails applications. One common area of oversight is the lack or misconfiguration of Postgresql indexes. Despite the associated disk storage costs and potential impact on write speed, indexing is often beneficial, especially for read-intensive applications.

Accurate performance assessment necessitates access to the production database. This article will explore two methods for identifying and rectifying index-related inefficiencies in Postgresql within a Rails environment.

Find Missing Postgresql Indexes Using pg_stat_all_tables

To start, pg_stat_all_tables is a system view in Postgresql that gives you a snapshot of your table activities, like sequential and index scans. This data is indispensable for identifying where you might need additional indexes.

Consider the following SQL query designed to highlight tables in need of indexing:

SELECT
  relname,
  seq_scan - idx_scan AS too_much_seq,
  CASE
    WHEN seq_scan - coalesce(idx_scan, 0) > 0 THEN 'Missing Index'
    ELSE 'OK'
  END,
  pg_relation_size(relname::regclass) AS rel_size
FROM
  pg_stat_all_tables
WHERE
  schemaname = 'public' AND pg_relation_size(relname::regclass) > 80000 -- adjust threshold as needed
ORDER BY
  too_much_seq DESC;

The query evaluates tables in the public schema and arranges them based on the differential between sequential scans (seq_scan) and index scans (idx_scan). A positive differential likely indicates a missing index. The condition pg_relation_size(relname::regclass) > 80000 is included to account for the potential advantage of sequential scans over index scans for small tables. (80000 is an arbitrary threshold which worked fine where I've implemented this for clients)

Note that this query tells you which tables might need indexing, but not which columns. For that, you'll need to dig into your application logs or consider adding indexes on foreign keys (wherever they are missing).

Measure Index Efficiency Using pg_statio_user_tables

The system view pg_statio_user_tables is another invaluable resource for understanding index utilization within tables. It's like a more advanced sibling of pg_stat_all_tables, revealing which tables are using their indexes efficiently.

Below is a SQL query to gauge index efficiency:

SELECT
  relname AS table_name,
  (idx_blks_hit * 1.0 / (idx_blks_hit + idx_blks_read)) AS index_efficiency
FROM
  pg_statio_user_tables
WHERE
  idx_blks_read + idx_blks_hit > 0 -- To avoid division by zero
ORDER BY
  index_efficiency ASC
LIMIT 10; -- Adjust limit as needed

The query calculates index_efficiency by dividing the index cache hits (idx_blks_hit) by the total number of index reads (idx_blks_hit + idx_blks_read). A lower efficiency score here is a red flag that your indexes aren't pulling their weight.

Low index_efficiency can imply indexes on the wrong columns or perhaps the wrong type of index altogether. Postgresql offers several types of indexes (like B-trees, Hash, etc.), and picking the wrong one can have consequences. Also, small tables may not benefit from indexes at all.

Conclusion

In Rails applications, optimizing your Postgresql database often comes down to smart indexing. Using Postgresql system views like pg_stat_all_tables and pg_statio_user_tables, you can identify potential bottlenecks and improve performance. Always remember, the numbers don't lie; if you're missing indexes or have inefficient ones, these metrics will make it clear. Happy indexing!

Supercharge Your Rails App

Upgrade Your Tech Stack for a Smoother Dev Experience and Increased Profits.

Order a Review