Chỉ mục cơ sở dữ liệu là mối quan tâm của các nhà phát triển. Chúng có tiềm năng cải thiện hiệu suất của các tính năng tìm kiếm và lọc sử dụng truy vấn SQL trong phần phụ trợ. Trong phần thứ hai của loạt bài viết này, tôi sẽ chỉ ra tác động của chỉ mục cơ sở dữ liệu trong việc tăng tốc bộ lọc bằng ứng dụng web Java được phát triển với Spring Boot và Vaadin.
Đọc phần 1 của loạt bài này nếu bạn muốn tìm hiểu cách hoạt động của ứng dụng mẫu mà chúng tôi sẽ sử dụng ở đây. Bạn có thể tìm thấy mã trên GitHub. Ngoài ra, và nếu bạn thích, tôi đã quay một phiên bản video của bài viết này:
Yêu cầu
Chúng tôi có một trang web có lưới hiển thị danh sách sách từ cơ sở dữ liệu MariaDB:
Chúng tôi muốn thêm bộ lọc để cho phép người dùng trang này xem sách nào đã được xuất bản vào một ngày nhất định.
Triển khai Dịch vụ và Truy vấn Kho lưu trữ
Chúng tôi phải thực hiện một số thay đổi trong phần phụ trợ để hỗ trợ lọc dữ liệu trước ngày xuất bản. Trong lớp kho lưu trữ, chúng ta có thể thêm phương thức sau:
@Repository
public interface BookRepository extends JpaRepository<Book, Integer> {
Page<Book> findByPublishDate(LocalDate publishDate, Pageable pageable);
}
Điều này sử dụng tính năng tải chậm như chúng ta đã thấy trong phần 1 của loạt bài viết này. Chúng tôi không phải triển khai phương pháp này — Dữ liệu mùa xuân sẽ tạo nó cho chúng tôi trong thời gian chạy.
Chúng ta cũng phải thêm một phương thức mới vào lớp dịch vụ (là lớp mà giao diện người dùng sử dụng để chạy logic nghiệp vụ). Đây là cách thực hiện:
@Service
public class BookService {
private final BookRepository repository;
...
public Stream<Book> findAll(LocalDate publishDate, int page, int pageSize) {
return repository.findByPublishDate(publishDate, PageRequest.of(page, pageSize)).stream();
}
}
Thêm bộ lọc vào trang web
Với phần phụ trợ hỗ trợ lọc sách theo ngày xuất bản, chúng tôi có thể thêm bộ chọn ngày vào triển khai trang web (hoặc chế độ xem):
@Route("")
public class BooksView extends VerticalLayout {
public BooksView(BookService service) {
...
var filter = new DatePicker("Filter by publish date");
filter.addValueChangeListener(event ->
grid.setItems(query ->
service.findAll(filter.getValue(), query.getPage(), query.getPageSize())
)
);
add(filter, grid);
setSizeFull();
}
...
}
Mã này chỉ tạo một DatePicker
mới đối tượng lắng nghe những thay đổi trong giá trị của nó (thông qua một trình nghe thay đổi giá trị). Khi giá trị thay đổi, chúng tôi sử dụng lớp dịch vụ để nhận sách được xuất bản vào ngày mà người dùng đã chọn. Các sách phù hợp sau đó được đặt làm các mục của Grid
.
Kiểm tra truy vấn chậm
Chúng tôi đã triển khai bộ lọc; tuy nhiên, nó cực kỳ chậm nếu bạn có, chẳng hạn như 200 nghìn hàng trong bảng. Thử nó! Tôi đã viết một bài báo giải thích cách tạo dữ liệu demo thực tế cho các ứng dụng Java. Với số hàng này, ứng dụng mất vài giây để hiển thị dữ liệu trên trang web trên máy của tôi (MacBook Pro 2,3 GHz Quad-Core Intel Core i5). Điều này hoàn toàn làm hỏng trải nghiệm người dùng.
Phân tích truy vấn với "Giải thích truy vấn"
Nếu bạn đã bật ghi nhật ký truy vấn, bạn có thể tìm truy vấn được tạo bởi Hibernate trong nhật ký của máy chủ. Sao chép nó, thay thế các dấu hỏi bằng các giá trị thực và chạy nó trong một ứng dụng khách cơ sở dữ liệu SQL. Trên thực tế, tôi có thể giúp bạn tiết kiệm thời gian. Đây là phiên bản đơn giản của truy vấn:
SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';
MariaDB bao gồm EXPLAIN
cung cấp cho chúng tôi thông tin hữu ích về cách công cụ ước tính sẽ chạy truy vấn. Để sử dụng nó, chỉ cần thêm EXPLAIN
trước truy vấn:
EXPLAIN SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';
Đây là kết quả:
Tài liệu có mọi thứ bạn cần biết về nó, nhưng điều quan trọng là giá trị trong loại cột: TẤT CẢ . Giá trị này cho chúng ta biết rằng công cụ ước tính rằng nó sẽ phải tìm nạp hoặc đọc tất cả các hàng trong bảng. Không phải là một điều tốt.
Tạo chỉ mục
May mắn thay, chúng tôi có thể dễ dàng khắc phục điều này bằng cách tạo một chỉ mục trên cột mà chúng tôi đang sử dụng để lọc dữ liệu:publish_date
. Đây là cách thực hiện:
CREATE INDEX book\_publish\_date_index ON book(publish_date);
Chỉ mục cơ sở dữ liệu là một cấu trúc dữ liệu được tạo bởi engine, thường là một cây b ( b cho cân bằng ), và điều đó đẩy nhanh quá trình tìm kiếm một hàng nhất định trong bảng, tức là tìm kiếm một hàng được cung cấp giá trị trong cột mà chỉ mục được tạo. Quá trình này nhanh hơn nhờ bản chất của cây b — chúng giữ dữ liệu theo thứ tự giúp giảm độ phức tạp về thời gian từ O (N) đến O (log (N)) và thậm chí O (log (1)) trong một số trường hợp.
Kiểm tra Cải tiến
Với chỉ mục được tạo, chúng tôi có thể chạy lại câu lệnh EXPLAIN và thấy rằng cột loại hiển thị giá trị ref thay vì TẤT CẢ :
ref giá trị có nghĩa là công cụ sẽ sử dụng chỉ mục khi chúng tôi chạy truy vấn. Điều quan trọng là bạn phải kiểm tra điều này khi bạn thêm chỉ mục vào các truy vấn phức tạp hơn của mình. Luôn sử dụng EXPLAIN
tuyên bố để kiểm tra kỹ xem bạn có đang đạt được hiệu suất khi bạn giới thiệu một chỉ mục.
Nếu bạn thử ứng dụng web trong trình duyệt và chọn một ngày khác trong bộ chọn ngày (không cần khởi động lại máy chủ), bạn sẽ thấy sự khác biệt rất lớn! Ví dụ:dữ liệu được truy xuất trong vòng chưa đầy một giây trên máy của tôi trái ngược với vài giây trước khi chúng tôi tạo chỉ mục!