Yash/Backend Engineer
Interview / Contact
Back to Blog

How I Improved Spring Boot Performance by 30% at WageNest

6 min readYaswanth Reddy Koduru
Spring BootPerformanceJPAHibernateOptimization

How I Improved Spring Boot Performance by 30% at WageNest

At WageNest, our payroll processing system was handling increasing transaction volumes, but response times were creeping up. After profiling and optimization, we achieved a 25-30% performance improvement. Here's how.

The Performance Problem

Our Spring Boot microservices were showing:

  • API response times averaging 800-1200ms
  • Database connection pool exhaustion during peak hours
  • Slow JPA queries with N+1 problems
  • Redis cache misses on frequently accessed data

For a payroll system processing thousands of transactions daily, this wasn't acceptable.

Optimization Strategy

1. JPA/Hibernate Query Optimization

Problem: N+1 queries were killing performance.

Solution:

// Before: N+1 query problem
@OneToMany(mappedBy = "employee")
private List<PayrollTransaction> transactions;

// After: Eager fetch with JOIN FETCH
@Query("SELECT e FROM Employee e " +
       "JOIN FETCH e.transactions " +
       "WHERE e.tenantId = :tenantId")
List<Employee> findAllWithTransactions(@Param("tenantId") Long tenantId);

We also added:

  • Entity graphs for complex joins
  • Batch fetching where appropriate
  • Query hints for optimizer guidance

2. Database Indexing

Created composite indexes on frequently queried columns:

CREATE INDEX idx_payroll_tenant_date 
ON payroll_transactions(tenant_id, process_date, status);

CREATE INDEX idx_employee_tenant_active 
ON employees(tenant_id, is_active);

3. Redis Caching Strategy

Implemented multi-level caching:

@Cacheable(value = "employees", key = "#tenantId + '-' + #employeeId")
public Employee getEmployee(Long tenantId, Long employeeId) {
    return employeeRepository.findById(employeeId);
}

@CacheEvict(value = "employees", key = "#tenantId + '-' + #employee.id")
public Employee updateEmployee(Long tenantId, Employee employee) {
    return employeeRepository.save(employee);
}

4. Connection Pool Tuning

Optimized HikariCP configuration:

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000

Results

After optimization:

  • Average API response time: 300-500ms (60% improvement)
  • Database connection pool utilization: 40% (down from 95%)
  • Cache hit rate: 85%
  • Throughput: +40% transactions per second

Key Takeaways

  1. Profile before optimizing - Use Spring Boot Actuator + Micrometer
  2. N+1 queries are everywhere - Always use JOIN FETCH
  3. Indexes matter - Composite indexes for multi-column queries
  4. Cache strategically - Not everything needs caching
  5. Monitor continuously - Performance degrades over time

Building high-performance Spring Boot systems? Let's discuss optimization strategies.