Full-Text Index #
Dalam banyak sistem backend modern, pencarian teks adalah fitur yang tidak bisa dihindari: search artikel, search produk, search log, search knowledge base, dan sebagainya. Masalahnya, query pencarian teks yang salah bisa menjadi mimpi buruk bagi database.
Di sinilah Full-Text Index (FTI) hadir. Ia sering disebut sebagai solusi cepat untuk pencarian teks, tapi di saat yang sama juga sering disalahgunakan.
Artikel ini akan membahas:
- Apa itu Full-Text Index
- Bagaimana cara kerjanya
- Kenapa ia bisa sangat mempengaruhi performa query database
- Kesalahan umum penggunaan Full-Text Index
- Best practice optimasi query Full-Text Index
Apa Itu Full-Text Index? #
Full-Text Index adalah jenis index khusus yang dirancang untuk melakukan pencarian teks berbasis kata (token), bukan pencocokan string mentah seperti LIKE '%keyword%'.
Berbeda dengan B-Tree index yang bekerja pada:
- equality (
=) - range (
<,>,BETWEEN)
Full-Text Index bekerja pada:
- kata
- frasa
- relevansi
- ranking hasil
Contoh use case:
- Search artikel berdasarkan isi konten
- Search produk berdasarkan deskripsi
- Search komentar atau review
Kenapa LIKE '%keyword%' Itu Buruk?
#
Sebelum memahami Full-Text Index, kita perlu tahu kenapa solusi klasik ini bermasalah:
SELECT * FROM articles WHERE content LIKE '%database%';
Masalahnya:
- Tidak bisa memakai index B-Tree
- Database melakukan full table scan
- Kompleksitas O(n) terhadap jumlah row
- Semakin besar data → semakin lambat
Di tabel besar, query ini adalah performance killer.
Cara Kerja Full-Text Index (Secara Konseptual) #
Full-Text Index menggunakan konsep inverted index.
Alih-alih:
Row → Konten
Database menyimpan:
Kata → List Row ID
Contoh:
| Kata | Row ID |
|---|---|
| database | 1, 3, 7 |
| index | 2, 3 |
| performance | 1, 7 |
Saat query:
MATCH(content) AGAINST('database index')
Database cukup:
- Cari kata
databasedanindex - Ambil intersection row ID
- Hitung relevansi
Tanpa membaca seluruh tabel.
Contoh Full-Text Index di Database #
MySQL / MariaDB #
ALTER TABLE articles
ADD FULLTEXT INDEX ft_content (title, content);
Query:
SELECT *
FROM articles
WHERE MATCH(title, content)
AGAINST('database index' IN NATURAL LANGUAGE MODE);
PostgreSQL (FTS) #
PostgreSQL menggunakan tsvector dan tsquery:
CREATE INDEX idx_articles_fts
ON articles USING GIN(to_tsvector('english', content));
Query:
SELECT *
FROM articles
WHERE to_tsvector('english', content)
@@ to_tsquery('database & index');
Kenapa Full-Text Index Bisa Sangat Mempengaruhi Database? #
Index Size Bisa Sangat Besar #
Full-Text Index:
- Menyimpan setiap kata
- Menyimpan mapping kata → row
Akibatnya:
- Ukuran index bisa lebih besar dari tabel utama
- Membebani disk dan memory
Cost Tinggi Saat INSERT / UPDATE #
Setiap kali data berubah:
- Tokenisasi ulang teks
- Update inverted index
Efeknya:
- INSERT lebih lambat
- UPDATE kolom teks lebih mahal
Terutama pada kolom:
- artikel panjang
- deskripsi besar
- log
Ranking & Relevansi Itu Mahal #
Full-Text Index tidak hanya mencari data, tapi juga:
- Menghitung relevansi
- Memberi score
- Sorting hasil
Query ini:
ORDER BY MATCH(content) AGAINST('keyword') DESC
Lebih mahal dibanding query equality biasa.
Bisa Menghasilkan Result Set Besar #
Keyword umum seperti:
- “data”
- “system”
- “user”
Bisa menghasilkan:
- Ribuan row
- Transfer network besar
- Bottleneck di layer aplikasi
Kesalahan Umum Penggunaan Full-Text Index #
❌ Menganggap Full-Text Index Sebagai Solusi Segalanya #
Full-Text Index bukan pengganti:
- filter by status
- filter by tenant
- filter by date
Query buruk:
SELECT *
FROM articles
WHERE MATCH(content) AGAINST('database');
Tanpa filter lain → result besar.
❌ Tidak Menggabungkan Dengan Filter Biasa #
Seharusnya:
SELECT *
FROM articles
WHERE status = 'published'
AND MATCH(content) AGAINST('database');
Filter non-FTI membantu memperkecil search space.
❌ Index Full-Text di Semua Kolom #
Mengindex:
- title
- content
- notes
- metadata
Sekaligus → index membengkak dan update mahal.
Best Practice Optimasi Full-Text Index #
Gunakan Full-Text Index Hanya untuk Kolom yang Tepat #
Ideal:
- article content
- product description
Hindari:
- kolom kecil
- kolom yang sering berubah
Selalu Kombinasikan Dengan Filter Lain #
WHERE tenant_id = ?
AND status = 'active'
AND MATCH(content) AGAINST(?);
Tujuan:
- Perkecil kandidat row
- Kurangi cost ranking
Batasi Result dengan LIMIT #
ORDER BY relevance DESC
LIMIT 20;
FTI tanpa LIMIT adalah undangan masalah.
Gunakan Mode yang Tepat #
MySQL:
NATURAL LANGUAGE MODEBOOLEAN MODE
Gunakan BOOLEAN MODE jika:
- ingin kontrol kata wajib (
+word) - ingin exclude (
-word)
Jangan Takut Pisahkan Search ke Engine Khusus #
Jika:
- data sangat besar
- search sangat kompleks
- traffic tinggi
Pertimbangkan:
- Elasticsearch
- OpenSearch
- Meilisearch
Database utama tetap fokus pada:
- transaksi
- konsistensi
Kesimpulan #
Full-Text Index adalah:
- Sangat cepat untuk pencarian teks
- Sangat mahal jika disalahgunakan
Gunakan jika:
- Memang butuh search teks
- Sudah dipadukan dengan filter lain
- Result dibatasi
Hindari jika:
- Sekadar ingin
LIKE '%keyword%' - Data kecil
- Query jarang dipakai
Full-Text Index bukan sekadar index — ia adalah subsystem search mini di dalam database.
Gunakan dengan sadar, bukan refleks.