Does PostgreSQL support Row Store Index?

PostgreSQL does not have a dedicated Row Store Index as a specific index type because it fundamentally follows a row-oriented storage model where data is stored row by row in tables. However, PostgreSQL supports a variety of index types and features that can achieve similar goals depending on the use case.


Understanding Row Store Index

  • A Row Store Index is typically associated with databases that use columnar storage, where a separate index or mechanism exists to facilitate fast retrieval of rows across columns.
  • In PostgreSQL, the default storage format is row-oriented, and therefore, data retrieval is already row-based. Index types in PostgreSQL optimize access to specific rows based on column values, eliminating the explicit need for a row store index.

Index Types in PostgreSQL Relevant to Row Store Needs

PostgreSQL provides multiple index types that support efficient row retrieval based on conditions:

1. B-Tree Index (Default)

  • B-Tree is the most commonly used index type, and it supports equality and range queries efficiently.
  • Use Case: Retrieve rows based on ordered or unique values in columns.
  • Example:
CREATE INDEX idx_orders_customer_id ON orders (customer_id);
SELECT * FROM orders WHERE customer_id = 12345;

2. GIN (Generalized Inverted Index)

  • Designed for indexing composite data types like arrays, JSONB, or full-text search.
  • Use Case: Efficient retrieval of rows with array or document-based data structures.
  • Example:
CREATE INDEX idx_orders_meta ON orders USING GIN (meta);
SELECT * FROM orders WHERE meta @> '{"key": "value"}';

3. BRIN (Block Range Index)

  • Stores metadata for ranges of table blocks, optimized for sequential access to rows.
  • Use Case: Works well for large tables where data is inserted sequentially, such as logs or time-series data.
  • Example:
CREATE INDEX idx_transactions_date ON transactions USING BRIN (transaction_date);
SELECT * FROM transactions WHERE transaction_date BETWEEN '2023-01-01' AND '2023-01-31';

4. Covering Index (INCLUDE Clause)

  • Extends a B-Tree index to include additional columns that are not part of the index key but can be fetched directly.
  • Use Case: Avoids fetching rows from the heap for queries using indexed columns and included columns.
  • Example:
CREATE INDEX idx_orders_customer_id_incl ON orders (customer_id) INCLUDE (status, created_at);
SELECT status, created_at FROM orders WHERE customer_id = 12345;

PostgreSQL Features That Simulate Row Store Index Behavior

1. Index-Only Scans

  • PostgreSQL supports Index-Only Scans, where the index itself contains all the data needed for a query, eliminating the need to access the main table (heap).
  • How it Helps: Works like a "row store index" by fetching data efficiently if all required columns are in the index.
  • Example:
CREATE INDEX idx_orders_customer_id_status ON orders (customer_id, status);
SELECT customer_id, status FROM orders WHERE customer_id = 12345;

2. Materialized Views

  • Materialized views can act as a precomputed row store, providing optimized access to commonly queried row combinations.
  • How it Helps: For repetitive complex queries, the materialized view serves as a "snapshot" of rows.
  • Example:
CREATE MATERIALIZED VIEW mv_orders_summary AS
SELECT customer_id, COUNT(*) AS total_orders
FROM orders
GROUP BY customer_id;

3. Partitioning

  • Declarative partitioning allows dividing a table into smaller, row-oriented storage units based on column values.
  • How it Helps: Limits the rows scanned by queries to specific partitions, mimicking row store indexing behavior.
  • Example:
CREATE TABLE transactions (
    transaction_id SERIAL,
    transaction_date DATE,
    amount NUMERIC
) PARTITION BY RANGE (transaction_date);

When to Use Alternatives

If you're looking for advanced row-based optimizations that mimic a row store index, consider using:

  • TimescaleDB (PostgreSQL Extension): Provides native support for time-series data and row-oriented optimizations.
  • Columnar Storage: Use extensions like cstore_fdw for columnar data storage if the workload involves analytical queries.

Conclusion

PostgreSQL does not explicitly have a Row Store Index because its default row-oriented storage and various index types (e.g., B-Tree, BRIN, GIN) already optimize row-based access. Features like index-only scans, covering indexes, and partitioning provide functionality equivalent to row store indexing in most use cases.

Implementing the Materialized Path Model in PostgreSQL: A Step-by-Step Guide

How Materialised Views work in PostgreSQL?

 

PostgreSQL Indexes

About Shiv Iyer 500 Articles
Open Source Database Systems Engineer with a deep understanding of Optimizer Internals, Performance Engineering, Scalability and Data SRE. Shiv currently is the Founder, Investor, Board Member and CEO of multiple Database Systems Infrastructure Operations companies in the Transaction Processing Computing and ColumnStores ecosystem. He is also a frequent speaker in open source software conferences globally.