Lesson 3.4: Expression Indexes
Indexing Computed Values
SELECT * FROM users WHERE LOWER(email) = 'alice@example.com';
CREATE INDEX users_email_idx ON users(email);
CREATE INDEX users_email_lower_idx ON users(LOWER(email));
SELECT * FROM users WHERE LOWER(email) = 'alice@example.com';
Common Expression Index Patterns
1. Case-insensitive searches:
CREATE INDEX products_name_lower_idx ON products(LOWER(name));
SELECT * FROM products WHERE LOWER(name) = LOWER('iPhone');
2. Date truncation:
CREATE INDEX logs_date_idx ON logs(DATE(created_at));
SELECT DATE(created_at), COUNT(*)
FROM logs
GROUP BY DATE(created_at);
3. JSONB field extraction:
CREATE INDEX products_price_idx ON products((metadata->>'price')::numeric);
SELECT * FROM products
WHERE (metadata->>'price')::numeric < 100;
4. Full-text search (tsvector):
CREATE INDEX documents_search_idx ON documents
USING GIN(to_tsvector('english', content));
SELECT * FROM documents
WHERE to_tsvector('english', content) @@ to_tsquery('AI & agents');
Expression Indexes for AI
Embedding dimensions:
CREATE INDEX embeddings_dim_0_10_idx ON embeddings(
(vector[1:10])::vector(10)
);
Feature normalization:
CREATE INDEX features_normalized_idx ON user_features(
(feature_value / GREATEST(feature_max, 1))
);
Key Takeaways
- Expression indexes index the result of a function or expression
- Query must use the exact same expression to use the index
- Essential for case-insensitive searches, date truncation, and JSONB queries
- Full-text search requires GIN index on tsvector expressions
- More expensive to maintain (expression computed on every insert/update)
- Useful for AI workloads that transform features or extract JSON fields