Khi phát triển ứng dụng Java, một trong những vấn đề phổ biến mà chúng ta phải đối mặt là tối ưu hóa hiệu suất khi làm việc với dữ liệu lớn từ cơ sở dữ liệu. Đặc biệt, khi cần lấy thông tin liên quan từ nhiều bảng khác nhau hoặc khi cần thực hiện nhiều truy vấn trong một vòng lặp, việc tối ưu hóa mã nguồn là rất quan trọng để tránh làm giảm hiệu suất ứng dụng.
Trong bài viết này, chúng ta sẽ xem xét một trường hợp điển hình trong đó việc tối ưu hóa vòng lặp có thể cải thiện hiệu suất rất lớn. Vấn đề Giả sử bạn có một danh sách người dùng (UserDetailVo) và muốn tạo một đối tượng ExpertVo cho mỗi người dùng này. Mỗi ExpertVo sẽ chứa thông tin về các lĩnh vực chuyên môn mà người dùng đó tham gia. Thông thường, bạn sẽ cần truy vấn dữ liệu các lĩnh vực chuyên môn (ExpertField) của từng người dùng từ cơ sở dữ liệu.
Tuy nhiên, nếu bạn thực hiện các truy vấn trong mỗi vòng lặp qua danh sách người dùng, bạn sẽ gặp phải vấn đề về hiệu suất khi số lượng người dùng và dữ liệu rất lớn. Điều này có thể dẫn đến việc ứng dụng bị chậm hoặc thậm chí bị timeout nếu có quá nhiều truy vấn.
Giải pháp tối ưu Để giải quyết vấn đề này, thay vì thực hiện nhiều truy vấn trong vòng lặp, chúng ta có thể làm như sau:
Lấy tất cả các dữ liệu cần thiết một lần: Thay vì gọi truy vấn trong mỗi vòng lặp, chúng ta có thể lấy tất cả các ExpertField và CategoryVo cần thiết trước. Sử dụng Map để tra cứu nhanh: Thay vì lặp qua toàn bộ danh sách các CategoryVo cho mỗi ExpertField, chúng ta có thể sử dụng Map để tra cứu các CategoryVo theo fieldId và giảm thiểu số lần lặp lại.
// Lấy tất cả ExpertField một lần từ cơ sở dữ liệu List<ExpertField> allExpertFields = expertFieldRepo.findAll();
// Lấy tất cả CategoryVo và tạo map theo fieldId để tra cứu nhanh Map<String, CategoryVo> categoryVoMap = new HashMap<>(); for (CategoryVo categoryVo : categoryVoArrayList) { categoryVoMap.put(categoryVo.getId(), categoryVo); }
if (!detailVos.isEmpty()) { List<ExpertVo> expertVos = new ArrayList<>();
// Duyệt qua tất cả các UserDetailVo (1 vòng)
for (UserDetailVo detailVo : detailVos) { ExpertVo expertVo = new ExpertVo(); expertVo.setId(detailVo.getId()); expertVo.setDisplayName(detailVo.getDisplayName()); expertVo.setName(detailVo.getName()); if (SecurityContext.getUserInfo() != null) { expertVo.setPhoneNumber(detailVo.getPhoneNumber()); } // Tạo danh sách CategoryVo cho ExpertVo trong vòng lặp này (1 vòng) List<CategoryVo> categoryVoArray = new ArrayList<>(); // Duyệt qua tất cả các ExpertField và chọn ra các CategoryVo phù hợp (kết hợp với map) (1 vòng) for (ExpertField expertField : allExpertFields) { if (expertField.getExpertId().equals(detailVo.getId())) { CategoryVo categoryVo = categoryVoMap.get(expertField.getFieldId()); if (categoryVo != null) { categoryVoArray.add(categoryVo); } } } expertVo.setFieldVos(categoryVoArray); expertVos.add(expertVo);
}
}