Database performance is critical for application scalability. Here are proven optimization techniques.

1. Indexing Strategy

When to Index

-- Index frequently queried columns
CREATE INDEX idx_user_email ON users(email);

-- Index foreign keys
CREATE INDEX idx_post_user_id ON posts(user_id);

-- Composite indexes for multi-column queries
CREATE INDEX idx_user_status_role ON users(status, role);

When NOT to Index

  • Columns with low cardinality (few unique values)
  • Frequently updated columns
  • Small tables (< 1000 rows)

2. Query Optimization

Avoid SELECT *

-- Bad
SELECT * FROM users WHERE id = 123;

-- Good
SELECT id, name, email FROM users WHERE id = 123;

Use LIMIT

-- Always limit large result sets
SELECT * FROM posts ORDER BY created_at DESC LIMIT 20;

Avoid N+1 Queries

// Bad: N+1 queries
users.forEach(user => {
  const posts = db.query('SELECT * FROM posts WHERE user_id = ?', [user.id]);
});

// Good: Single query with JOIN
const usersWithPosts = db.query(`
  SELECT u.*, p.* 
  FROM users u
  LEFT JOIN posts p ON u.id = p.user_id
`);

3. Connection Pooling

// Configure connection pool
const pool = mysql.createPool({
  connectionLimit: 10,
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'mydb',
  waitForConnections: true,
  queueLimit: 0
});

4. Caching

Application-Level Caching

// Cache frequently accessed data
const cache = new Map();

async function getUser(id) {
  if (cache.has(id)) {
    return cache.get(id);
  }
  
  const user = await db.query('SELECT * FROM users WHERE id = ?', [id]);
  cache.set(id, user);
  return user;
}

Query Result Caching

-- Use query cache (MySQL)
SET GLOBAL query_cache_size = 67108864;
SET GLOBAL query_cache_type = 1;

5. Database Schema Optimization

Normalize Properly

-- Avoid over-normalization
-- Balance between normalization and performance

Use Appropriate Data Types

-- Use smallest appropriate type
TINYINT instead of INT for small numbers
VARCHAR(255) instead of TEXT when possible
DATE instead of DATETIME when time not needed

6. Partitioning

-- Partition large tables by date
CREATE TABLE logs (
  id INT,
  created_at DATE,
  data TEXT
) PARTITION BY RANGE (YEAR(created_at)) (
  PARTITION p2023 VALUES LESS THAN (2024),
  PARTITION p2024 VALUES LESS THAN (2025),
  PARTITION p2025 VALUES LESS THAN (2026)
);

7. Query Analysis

EXPLAIN Plan

EXPLAIN SELECT * FROM users WHERE email = '[email protected]';

Slow Query Log

-- Enable slow query log
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

8. Batch Operations

// Bad: Multiple individual inserts
users.forEach(user => {
  db.query('INSERT INTO users (name, email) VALUES (?, ?)', [user.name, user.email]);
});

// Good: Batch insert
const values = users.map(u => [u.name, u.email]);
db.query('INSERT INTO users (name, email) VALUES ?', [values]);

9. Database Maintenance

Regular Vacuuming (PostgreSQL)

VACUUM ANALYZE;

Optimize Tables (MySQL)

OPTIMIZE TABLE users;

10. Monitoring

  • Monitor query performance
  • Track slow queries
  • Monitor connection pool usage
  • Watch for table locks
  • Monitor disk I/O

Best Practices

  1. Index strategically
  2. Optimize queries
  3. Use connection pooling
  4. Implement caching
  5. Normalize appropriately
  6. Use appropriate data types
  7. Partition large tables
  8. Analyze query performance
  9. Batch operations
  10. Regular maintenance

Conclusion

Database optimization requires:

  • Strategic indexing
  • Query optimization
  • Proper caching
  • Regular monitoring
  • Maintenance routines

Optimize systematically for better performance! ๐Ÿš€