Working with large datasets can slow down your Firebird application if queries or memory usage are not managed properly. This guide explains practical techniques to efficiently handle big data in Spring Boot using pagination, streaming, and batch operations.
1. Use Pagination for Data Retrieval
When retrieving thousands of rows, always paginate results instead of loading everything into memory.
Here’s how to add pagination with Spring Data JPA:
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
Page<Employee> findAll(Pageable pageable);
}
Then, you can request pages in your service:
Page<Employee> employees = employeeRepository.findAll(PageRequest.of(0, 100));
employees.getContent().forEach(System.out::println);
This loads only 100 records per request, reducing memory consumption significantly.
2. Stream Data for Processing
If you need to process all records but don’t want to keep them in memory, use Java 8 streams.
@Query("SELECT e FROM Employee e")
Stream<Employee> streamAll();
And consume it efficiently:
try (Stream<Employee> stream = employeeRepository.streamAll()) {
stream.forEach(e -> processEmployee(e));
}
This approach keeps memory usage low because data is fetched lazily from Firebird.
3. Use Batch Inserts and Updates
When inserting or updating a large number of records, batch processing can dramatically improve performance.
Enable batch mode in your
application.properties:
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
Then, in your service:
@Transactional
public void saveEmployees(List<Employee> employees) {
for (int i = 0; i < employees.size(); i++) {
employeeRepository.save(employees.get(i));
if (i % 50 == 0) {
employeeRepository.flush();
}
}
}
This groups operations into batches, minimizing communication with the database.
4. Optimize Queries with Indexes
Firebird performs best when queries use proper indexes. Identify columns frequently used in filters or sorting and create indexes for them.
Example:
CREATE INDEX IDX_EMPLOYEE_DEPARTMENT ON EMPLOYEE(DEPARTMENT_ID);
You can verify query performance using Firebird’s
PLAN keyword or database monitoring tools.
5. Limit Fetch Size
Set the fetch size for the JDBC driver to control how many rows are retrieved per network call:
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setFetchSize(200);
This reduces network overhead for very large queries.
6. Use Stored Procedures for Heavy Computation
If your logic involves complex aggregations, consider moving it closer to the database with stored procedures.
Example Firebird procedure:
CREATE PROCEDURE GET_TOTAL_SALARY
RETURNS (TOTAL NUMERIC(15,2))
AS
BEGIN
SELECT SUM(SALARY) FROM EMPLOYEE INTO :TOTAL;
SUSPEND;
END
Then call it from Spring Boot:
@Query(value = "EXECUTE PROCEDURE GET_TOTAL_SALARY", nativeQuery = true)
BigDecimal getTotalSalary();
This minimizes data transfer and improves execution time.
image quote pre code