Database Optimization Techniques: Speed Up Your Queries by 10x
Introduction
Slow database queries are the #1 cause of poor application performance. Even with perfect frontend code, slow databases frustrate users. This guide covers proven database optimization techniques to speed up your queries by 10x or more.
For a complete backend architecture overview, read our Microservices Architecture Guide.
Understanding Database Slowdowns
Common causes of slow queries:
- Missing indexes
- Inefficient queries (SELECT *, no WHERE clauses)
- Unoptimized schema design
- Large result sets
- Lock contention
- Hardware limitations
Indexing Strategies
What are Indexes?
Indexes are data structures that improve query speed. Think of a book's index—finding a topic in seconds vs flipping every page.
When to Add Indexes
- Columns used in WHERE clauses
- Columns used in JOIN conditions
- Columns used in ORDER BY
- Columns used in GROUP BY
-- PostgreSQL index example
CREATE INDEX idx_users_email ON users(email);
-- Composite index for multiple columns
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
Index Types
- B-Tree: Default, good for equality and range queries
- Hash: Only equality, faster than B-Tree for exact matches
- GIN (PostgreSQL): For full-text search and array columns
- GiST (PostgreSQL): For geometric and full-text data
MongoDB Indexes
// Single field index
db.users.createIndex({ email: 1 });
// Compound index
db.orders.createIndex({ userId: 1, createdAt: -1 });
For MongoDB vs PostgreSQL decision, check our MongoDB vs PostgreSQL guide.
Query Optimization Techniques
Use EXPLAIN to Analyze Queries
-- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'user@example.com';
-- MySQL
EXPLAIN SELECT * FROM users WHERE email = 'user@example.com';
Avoid SELECT *
Only select columns you need. SELECT * loads unnecessary data.
-- Bad
SELECT * FROM users;
-- Good
SELECT id, name, email FROM users;
Use LIMIT for Large Results
SELECT * FROM orders WHERE user_id = 123 LIMIT 50;
Partition Large Tables
Split huge tables by date ranges or other logical boundaries.
Schema Design Best Practices
- Normalize for data integrity: Avoid data duplication
- Denormalize for read performance: Add computed fields
- Use appropriate data types: VARCHAR vs TEXT, INT vs BIGINT
- Add foreign keys: Maintains referential integrity
- Consider JSON columns for flexible schemas (PostgreSQL)
Caching Strategies
Database caching reduces load and speeds up repeated queries.
Redis for Caching
Cache query results, user sessions, and computed values in Redis.
// Node.js + Redis caching
async function getUser(id) {
const cached = await redis.get(`user:${id}`);
if (cached) return JSON.parse(cached);
const user = await db.query('SELECT * FROM users WHERE id = ?', [id]);
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
Database Maintenance
- Regular VACUUM (PostgreSQL): Reclaims storage
- ANALYZE: Updates statistics for query planner
- Reindex: Rebuilds corrupted indexes
- Archive old data: Move historical data to archive tables
Monitoring Database Performance
- pg_stat_statements (PostgreSQL)
- Performance Schema (MySQL)
- MongoDB Atlas Performance Advisor
- New Relic / DataDog for APM
For application performance monitoring, check our Web Performance Optimization Guide.
Conclusion
Start with proper indexes and EXPLAIN analysis. Most performance problems are solved by adding 2-3 indexes on frequently queried columns.
Need help optimizing your database? Contact our backend team or check our web development services.