Indeks database menjadi perhatian para pengembang. Mereka memiliki potensi untuk meningkatkan kinerja fitur pencarian dan filter yang menggunakan kueri SQL di backend. Di bagian kedua dari rangkaian artikel ini, saya akan menunjukkan dampak indeks database dalam mempercepat filter menggunakan aplikasi web Java yang dikembangkan dengan Spring Boot dan Vaadin.
Baca bagian 1 dari seri ini jika Anda ingin mempelajari cara kerja contoh aplikasi yang akan kami gunakan di sini. Anda dapat menemukan kodenya di GitHub. Juga, dan jika Anda mau, saya merekam versi video dari artikel ini:
Persyaratan
Kami memiliki halaman web dengan kisi yang menampilkan daftar buku dari database MariaDB:
Kami ingin menambahkan filter untuk memungkinkan pengguna halaman ini melihat buku mana yang diterbitkan pada tanggal tertentu.
Menerapkan Kueri dan Layanan Repositori
Kami harus membuat beberapa perubahan di backend untuk mendukung pemfilteran data pada tanggal publikasi. Di kelas repositori, kita dapat menambahkan metode berikut:
@Repository
public interface BookRepository extends JpaRepository<Book, Integer> {
Page<Book> findByPublishDate(LocalDate publishDate, Pageable pageable);
}
Ini menggunakan pemuatan lambat seperti yang kita lihat di bagian 1 dari rangkaian artikel ini. Kita tidak perlu mengimplementasikan metode ini—Spring Data akan membuatnya untuk kita saat runtime.
Kita juga harus menambahkan metode baru ke kelas layanan (yang merupakan kelas yang digunakan UI untuk menjalankan logika bisnis). Berikut caranya:
@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();
}
}
Menambahkan Filter ke Halaman Web
Dengan backend yang mendukung pemfilteran buku berdasarkan tanggal penerbitan, kami dapat menambahkan pemilih tanggal ke implementasi halaman web (atau tampilan):
@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();
}
...
}
Kode ini baru saja membuat DatePicker
baru objek yang mendengarkan perubahan nilainya (melalui pendengar perubahan nilai). Ketika nilai berubah, kami menggunakan kelas layanan untuk menerbitkan buku pada tanggal yang dipilih oleh pengguna. Buku yang cocok kemudian ditetapkan sebagai item dari Grid
.
Menguji Kueri Lambat
Kami telah menerapkan filter; namun, ini sangat lambat jika Anda memiliki, misalnya, 200 ribu baris dalam tabel. Cobalah! Saya menulis artikel yang menjelaskan cara menghasilkan data demo realistis untuk aplikasi Java. Dengan jumlah baris ini, aplikasi membutuhkan waktu beberapa detik untuk menampilkan data pada halaman web di komputer saya (MacBook Pro 2,3 GHz Quad-Core Intel Core i5). Ini benar-benar merusak pengalaman pengguna.
Menganalisis Query Dengan “Explain Query”
Jika Anda mengaktifkan pembuatan log kueri, Anda dapat menemukan kueri yang dihasilkan oleh Hibernate di log server. Salin, ganti tanda tanya dengan nilai aktual, dan jalankan di klien database SQL. Sebenarnya, saya bisa menghemat waktu Anda. Berikut adalah versi kueri yang disederhanakan:
SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';
MariaDB menyertakan EXPLAIN
pernyataan yang memberi kita informasi berguna tentang bagaimana mesin memperkirakan yang akan menjalankan kueri. Untuk menggunakannya, cukup tambahkan EXPLAIN
sebelum kueri:
EXPLAIN SELECT id, author, image_data, pages, publish_date, title
FROM book
WHERE publish_date = '2021-09-02';
Ini hasilnya:
Dokumentasi memiliki semua yang perlu Anda ketahui tentangnya, tetapi yang terpenting adalah nilai dalam jenis kolom:SEMUA . Nilai ini memberi tahu kita bahwa mesin memperkirakan bahwa ia harus mengambil atau membaca semua baris dalam tabel. Bukan hal yang baik.
Membuat Indeks
Untungnya, kita dapat dengan mudah memperbaikinya dengan membuat indeks pada kolom yang kita gunakan untuk memfilter data:publish_date
. Berikut caranya:
CREATE INDEX book\_publish\_date_index ON book(publish_date);
Indeks database adalah struktur data yang dibuat oleh mesin, biasanya b-tree (b untuk seimbang ), dan itu mempercepat proses menemukan baris tertentu dalam tabel, yaitu, mencari baris yang diberi nilai di kolom tempat indeks dibuat. Prosesnya lebih cepat berkat sifat b-tree—mereka menjaga data tetap teratur mengurangi kompleksitas waktu dari O(N) ke O(log(N)) dan bahkan O(log(1)) dalam beberapa kasus.
Menguji Peningkatan
Dengan indeks yang dibangun, kita dapat menjalankan pernyataan EXPLAIN lagi dan melihat bahwa kolom tipe menunjukkan nilai ref bukannya SEMUA :
Referensi nilai berarti mesin akan menggunakan indeks saat kita menjalankan kueri. Anda harus memeriksa ini saat menambahkan indeks ke kueri yang lebih kompleks. Selalu gunakan EXPLAIN
pernyataan untuk memeriksa kembali apakah Anda memperoleh kinerja saat Anda memperkenalkan indeks.
Jika Anda mencoba aplikasi web di browser dan memilih tanggal lain di pemilih tanggal (tidak perlu me-restart server), Anda akan melihat perbedaan besar! Misalnya, data diambil dalam waktu kurang dari satu detik di mesin saya, berbeda dengan beberapa detik sebelum kita membuat indeks!