wiki:Indexes

Version 2 (modified by 233194, 10 days ago) ( diff )

--

Indexes and performance analysis

Here we will cover the indexes that are not automatically created with PK/UK constraints, but would significantly improve performance in PC Forge. The focus is on the most frequent queries, JOIN operations and critical business scenarios.
With these indexes:
-Most frequent searches are covered (including build names, component names)
-Filtering by approval status and build dates is optimized
-JOIN operations between builds and components are faster
-Rating and favorite calculations are efficient
-Component type browsing is optimized

Scenario 1: Approved Builds Browsing and Filtering

Users frequently browse approved builds, filter them by name and sort by price, date or rating. This involves filtering by is_approved, searching by name and sorting by created_at or total_price.
Optimization: A composite index on is_approved and created_at speeds up the most common query pattern. Adding total_price allows for efficient sorting without additional table lookups.

CREATE INDEX IF NOT EXISTS idx_build_approved_date
ON build(is_approved, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_build_approved_price
ON build(is_approved, total_price DESC);

CREATE INDEX IF NOT EXISTS idx_build_name_search
ON build(name);

is_approved is a low-cardinality column (TRUE/FALSE), while both created_at and total_price are high-cardinality columns often used for ORDER BY, so that's why this combination is optimal.

Scenario 2: User Dashboard - Builds and Favorites

The user dashboard displays builds created by the user and also builds they've favorited, created by other users. This requires frequent lookups by user_id in both build and favorite_build tables, often with rating aggregations.
Optimization: Indexes on user_id in both tables, plus composite indexes for the JOIN operations between builds and ratings.

CREATE INDEX IF NOT EXISTS idx_build_user_id
ON build(user_id);

CREATE INDEX IF NOT EXISTS idx_favorite_build_user_id
ON favorite_build(user_id);

CREATE INDEX IF NOT EXISTS idx_rating_build_build_id
ON rating_build(build_id);

Scenario 3: Build Components and Compatibility Checking

When users view build details or add components to builds, the application performs frequent JOIN operations between build_component and components. Compatibility checking also requires lookups by component type and specific attributes (like socket, TDP, form factor, length).
Optimization: Composite indexes on the junction table and component type filtering.

CREATE INDEX IF NOT EXISTS idx_build_component_build_id
ON build_component(build_id);

CREATE INDEX IF NOT EXISTS idx_build_component_component_id
ON build_component(component_id);

CREATE INDEX IF NOT EXISTS idx_components_type_price
ON components(type, price DESC);

CREATE INDEX IF NOT EXISTS idx_components_name_search
ON components(name);

The composite index (type, price DESC) is really useful when it comes to component browsing dialogs, because they filter by type and sort by price by default.

Scenario 4: Admin Panel - Pending Approvals

Admins frequently check for pending builds and suggestions. This requires filtering by is_approved = FALSE for builds and status = 'pending' for component suggestions.
Optimization: Indexes on status columns with date ordering for priority sorting.

CREATE INDEX IF NOT EXISTS idx_build_pending_date
ON build(is_approved, created_at DESC)
WHERE is_approved = FALSE;

CREATE INDEX IF NOT EXISTS idx_suggestions_status
ON suggestions(status);

CREATE INDEX IF NOT EXISTS idx_suggestions_user_id
ON suggestions(user_id);

The partial index on build with WHERE is_approved = FALSE is smaller and more efficient, since admins only care about unapproved builds.

Scenario 5: Reviews and User Authentication

Users leave reviews on builds, commenting their likes and dislikes, and with that the application frequently looks up usernames for authentication and display purposes.
Optimization: Indexes for review lookups and username searches.

CREATE INDEX IF NOT EXISTS idx_review_build_id
ON review(build_id);

CREATE INDEX IF NOT EXISTS idx_review_user_id
ON review(user_id);

CREATE INDEX IF NOT EXISTS idx_users_username
ON users(username);

CREATE INDEX IF NOT EXISTS idx_users_email
ON users(email);

username and email are both UNIQUE, but explicit indexes improve login query performance and case-insensitive searches if needed.

Scenario 6: Component Compatibility - Socket and Form Factor Matching

When users add components to their builds, the compatibility logic frequently queries CPU sockets, motherboard sockets and cooler compatibility.
Optimization: Indexes on compatibility-critical columns.

CREATE INDEX IF NOT EXISTS idx_cpu_socket
ON cpu(socket);

CREATE INDEX IF NOT EXISTS idx_motherboard_socket
ON motherboard(socket);

CREATE INDEX IF NOT EXISTS idx_cooler_sockets_socket
ON cooler_cpu_sockets(socket);

CREATE INDEX IF NOT EXISTS idx_motherboard_form_factor
ON motherboard(form_factor);

Testing with EXPLAIN ANALYZE

Example test for scenario 4:

EXPLAIN (ANALYZE, BUFFERS)
SELECT b.id, b.name, b.created_at, b.total_price, u.username
FROM build b
JOIN users u ON u.id = b.user_id
WHERE b.is_approved = FALSE
ORDER BY b.created_at DESC
LIMIT 50;

Performance Comparison

Without partial index:

Index Scan using idx_build_approved_date on build b

Index Cond: (is_approved = false) Buffers: shared hit=150

Execution Time: 0.351 ms

With partial index:

Index Scan using idx_build_pending_date on build b

Buffers: shared hit=68 read=2

Execution Time: 0.219 ms

Result: The partial index improved query performance by dropping the execution time from 0.351ms to 0.219ms. Partial indexes are more efficient for frequently filtered subsets of data, so that's why they are ideal for the admin queries that only target pending builds.

Note: See TracWiki for help on using the wiki.