Kenapa indeksmu tidak dipakai
Sudah menambahkan indeks, tapi EXPLAIN masih menunjukkan pemindaian
sekuensial. Hampir selalu ini salah satu dari lima hal di bawah.
1. Tipe datanya tidak cocok
Ini yang paling sering dan paling tidak terlihat. Kolom varchar, kita
membandingkan dengan bilangan bulat:
-- id bertipe varchar, tapi dikirim sebagai integer
SELECT * FROM orders WHERE id = 42;
-- ERROR: operator does not exist: character varying = integerKalau sampai dieksekusi lewat parameter, kadang ia berubah jadi pemindaian sekuensial sunyi. Perbaiki sisi kuerinya:
SELECT * FROM orders WHERE id = '42';2. Fungsi di kolom yang diindeks
Indeks dibangun di atas nilai kolom, bukan hasil fungsinya.
-- indeks di lower(email) tidak akan dipakai oleh ini
WHERE lower(email) = 'arga@bayu.dev'
-- yang benar: indeks ekspresi
CREATE INDEX ON users (lower(email));3. Urutan kolom di indeks majemuk
Indeks di (a, b) bisa dipakai untuk filter a saja, atau a dan b. Tidak
untuk b saja. Ini yang paling sering saya lihat salah:
CREATE INDEX ON events (kind, created_at);
-- bisa: WHERE kind = 'x'
-- bisa: WHERE kind = 'x' AND created_at > now() - interval '1 day'
-- TIDAK bisa: WHERE created_at > now() - interval '1 day'Urutannya bukan soal estetika. Letakkan kolom yang disaring persis sama di depan, yang dipakai untuk rentang di belakang.
4. Selektivitas terlalu rendah
Kalau kondisi cocok dengan 40% baris, perencana akan memilih pemindaian sekuensial — dan itu keputusan yang benar. Membaca tabel berurutan lebih murah daripada melompat-lompat ke indeks lalu ke tabel.
5. Statistik usang
Perencana mengandalkan statistik. Kalau tabel berubah drastis tanpa
ANALYZE, pilihannya bisa salah.
ANALYZE orders;Jalankan ini dulu sebelum menyimpulkan sesuatu. Murah dan sering menyelesaikan.
Urutan pemeriksaan
Jalankan EXPLAIN (ANALYZE, BUFFERS), lalu bandingkan rows estimated dengan
rows actual. Kalau keduanya jauh berbeda, masalahnya ada di statistik atau
selektivitas, bukan di indeksnya.