🤖 Query Optimization
PostgreSQL ma query performance improve karva mate different techniques che. Let's explore kari ae.
EXPLAIN samajvo
EXPLAIN command query execution plan dekhade che - kevi rite PostgreSQL query execute karse ae.
Basic EXPLAIN
-- Simple execution plan
EXPLAIN SELECT * FROM users WHERE email = 'user@example.com';
-- Actual execution time sathe
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'user@example.com';
-- Detailed output - buffers, timing, everything
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS)
SELECT * FROM users WHERE email = 'user@example.com';
Output samajvo
Seq Scan on users (cost=0.00..18334.00 rows=1 width=264)
Filter: (email = 'user@example.com'::text)
- Seq Scan: Sequential scan (full table scan - slow for large tables)
- cost: Startup cost .. Total cost (lower is better)
- rows: Kitna rows return thashe (estimated)
- width: Average row size in bytes
Common Query Issues
N+1 Query Problem
Aa problem ORM use karta vadhare aave che.
❌ Bad Approach:
-- Pehla badha users fetch karo
SELECT * FROM users;
-- Tyar baad darek user mate orders (N queries!)
SELECT * FROM orders WHERE user_id = 1;
SELECT * FROM orders WHERE user_id = 2;
-- ... N vadhare queries
✅ Good Approach - Single JOIN query:
-- Ek j query ma badhu
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
SELECT * Avoid Karo
❌ Bad:
-- Badha columns fetch kare che (waste)
SELECT * FROM large_table WHERE id = 100;
✅ Good:
-- Faqat jaruri columns
SELECT id, name, email FROM large_table WHERE id = 100;
Index Optimization
Indexes query performance dramatically improve kare che, but sahi jagya pe use karva joiye.
Kada Index Create Karvu
-- WHERE clause ma use thata columns
CREATE INDEX idx_users_email ON users(email);
-- JOIN conditions mate
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- ORDER BY mate
CREATE INDEX idx_orders_created_at ON orders(created_at DESC);
-- Multiple columns mate composite index
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
Index Types
PostgreSQL ma different types of indexes che:
-- B-tree (default, most common)
CREATE INDEX idx_btree ON table_name(column_name);
-- Hash (equality checks mate j)
CREATE INDEX idx_hash ON table_name USING HASH(column_name);
-- GiST (geometric, full-text)
CREATE INDEX idx_gist ON table_name USING GIST(column_name);
-- GIN (arrays, JSONB, full-text)
CREATE INDEX idx_gin ON table_name USING GIN(jsonb_column);
-- BRIN (very large tables with natural ordering)
CREATE INDEX idx_brin ON logs USING BRIN(timestamp);
Partial Indexes
Faqat specific rows mate index - space bachay:
-- Faqat active users mate index
CREATE INDEX idx_active_users ON users(email)
WHERE status = 'active';
-- Recent records j index karo
CREATE INDEX idx_recent_orders ON orders(created_at)
WHERE created_at > '2024-01-01';
Covering Indexes
Index ma extra columns include karo - Index Only Scan possible bane:
-- email search ma name ane created_at pan joiye to
CREATE INDEX idx_users_email_covering ON users(email)
INCLUDE (name, created_at);
-- Have aa query index thi j answer thai shake (table access nai joitu)
SELECT name, created_at
FROM users
WHERE email = 'user@example.com';
Query Writing Best Practices
CTEs (Common Table Expressions)
Complex queries ne readable banavo:
-- Step by step breakdown
WITH active_users AS (
SELECT id, name FROM users WHERE status = 'active'
),
recent_orders AS (
SELECT user_id, COUNT(*) as order_count
FROM orders
WHERE created_at > CURRENT_DATE - INTERVAL '30 days'
GROUP BY user_id
)
SELECT
u.name,
COALESCE(o.order_count, 0) as orders
FROM active_users u
LEFT JOIN recent_orders o ON u.id = o.user_id;
EXISTS vs IN
Large datasets mate EXISTS often better performance ape che:
✅ EXISTS (Recommended):
-- EXISTS use karo - better performance
SELECT * FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);
❌ IN (Can be slower):
-- IN slow thai shake large subqueries sathe
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);
Pagination - LIMIT with ORDER BY
-- Basic pagination
SELECT id, name FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 0;
-- Large offsets slow che, keyset pagination better:
SELECT id, name FROM users
WHERE created_at < '2024-01-01 00:00:00'
ORDER BY created_at DESC
LIMIT 20;
Slow Queries Find Karo
Log Slow Queries
postgresql.conf ma configure karo:
# 1 second thi vadhare wala queries log karo
log_min_duration_statement = 1000
# Useful log format
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
pg_stat_statements Extension
Aa extension query statistics track kare che:
-- Extension enable karo
CREATE EXTENSION pg_stat_statements;
-- Slowest queries joyo
SELECT
query,
calls,
total_exec_time,
mean_exec_time,
max_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;
-- Most frequently executed queries
SELECT query, calls
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 10;
-- Reset statistics
SELECT pg_stat_statements_reset();
Useful Optimization Tips
- EXPLAIN ANALYZE Always - Optimize karta pehla actual plan joyo
- Index Smartly - Har column pe index na banavo, maintenance cost che
- VACUUM Regularly - Statistics update mate ane dead tuples clean karva mate
- Batch Operations - Bulk inserts/updates use karo where possible
- Connection Pooling - PgBouncer use karo connection overhead reduce karva
- Prepared Statements - Repeated queries mate planning overhead bachay
- Monitor Statistics - pg_stat tables regular check karo
Example: Index vs No Index
-- Without index
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'test@example.com';
-- Seq Scan: 1234.56 ms
-- Index create karo
CREATE INDEX idx_users_email ON users(email);
-- With index
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'test@example.com';
-- Index Scan: 0.12 ms (10000x faster!)
Next Steps: Configuration tuning shikhva mate (coming soon)