Foto oleh panumas nikhomkhai via Pexels

LIKE adalah operator pencarian pola teks di SQL Server yang sangat berguna ketika kita tidak tahu persis nilai yang dicari, misalnya mencari semua pelanggan yang namanya mengandung kata tertentu atau kode produk dengan pola tertentu. Namun LIKE yang ditulis sembarangan, terutama dengan wildcard di awal pola, bisa diam-diam menjadi penyebab query lambat pada tabel besar.

Artikel ini membahas wildcard yang dipakai bersama LIKE, dampaknya terhadap performa, dan alternatif yang lebih tepat untuk kebutuhan pencarian teks skala besar.

Wildcard Dasar pada LIKE

  • % — mewakili nol atau lebih karakter apa pun
  • _ — mewakili tepat satu karakter apa pun

Variasi wildcard % dan _

-- Nama yang diawali 'Budi' SELECT * FROM Customers WHERE FullName LIKE 'Budi%'; -- Nama yang mengandung kata 'tono' di mana saja SELECT * FROM Customers WHERE FullName LIKE '%tono%'; -- Kode produk dengan huruf kedua 'A', contoh 'XA123' SELECT * FROM Products WHERE ProductCode LIKE '_A%'; -- Expected: masing-masing query mengembalikan baris -- yang pola teksnya cocok sesuai posisi wildcard

Dampak Performa: Leading Wildcard

Pola '%tono%' yang diawali tanda % disebut leading wildcard. Pola ini memaksa SQL Server melakukan table scan penuh karena indeks standar tidak bisa dipakai untuk mencari di tengah atau akhir teks. Sebaliknya, pola 'Budi%' yang tidak diawali wildcard masih bisa memanfaatkan indeks lewat Index Seek.

Perbandingan logical reads leading vs trailing wildcard

SET STATISTICS IO ON; SELECT * FROM Customers WHERE FullName LIKE 'Budi%'; -- Expected: logical reads rendah jika ada index pada FullName SELECT * FROM Customers WHERE FullName LIKE '%tono%'; -- Expected: logical reads tinggi, scan count penuh meski index ada

Alternatif untuk Pencarian Teks Skala Besar

Untuk kebutuhan pencarian teks dalam jumlah besar dan kompleks seperti pencarian produk di e-commerce, Full-Text Search bawaan SQL Server atau mesin pencari khusus seperti Elasticsearch jauh lebih efisien dibanding LIKE dengan leading wildcard.

CONTAINS memakai Full-Text Index, bukan table scan

-- Setelah mengaktifkan Full-Text Index pada kolom ProductName SELECT ProductName FROM Products WHERE CONTAINS(ProductName, 'laptop'); -- Expected: hasil pencarian jauh lebih cepat pada tabel besar -- dibanding LIKE '%laptop%', karena memakai index khusus teks

Case Sensitivity pada LIKE

Perilaku LIKE terhadap huruf besar/kecil bergantung pada collation database. Pada collation default Bahasa Indonesia/Case-Insensitive yang umum dipakai, LIKE 'budi%' akan tetap cocok dengan 'Budi Santoso', namun pada collation case-sensitive hasilnya bisa berbeda.

Case sensitivity bergantung pada collation server/database

SELECT * FROM Customers WHERE FullName LIKE 'budi%'; -- Pada collation case-insensitive (default umum): cocok dengan 'Budi Santoso' -- Pada collation case-sensitive: TIDAK cocok dengan 'Budi Santoso'

Mengombinasikan LIKE dengan ESCAPE untuk Karakter Literal

Terkadang karakter % atau _ yang dicari memang bagian literal dari data, misalnya mencari produk dengan kode mengandung tanda underscore asli. SQL Server menyediakan klausa ESCAPE untuk menangani kasus ini.

Mencari underscore literal, bukan sebagai wildcard

SELECT ProductCode FROM Products WHERE ProductCode LIKE 'SKU\_%' ESCAPE '\'; -- Expected: hanya kode yang benar-benar mengandung underscore -- setelah 'SKU' yang cocok, bukan huruf sembarang di posisi itu

Tanpa ESCAPE, underscore pada pola selalu diartikan sebagai wildcard satu karakter, sehingga pencarian kode literal yang mengandung underscore bisa salah menangkap data yang sebenarnya tidak relevan.

Wildcard Lanjutan pada LIKE: Kurung Siku dan ESCAPE

Wildcard kurung siku [ ] dan penanganan karakter literal dengan ESCAPE

-- Mencari nama yang diawali huruf A, B, atau C SELECT ProductName FROM Products WHERE ProductName LIKE '[ABC]%'; -- Mencari nama yang TIDAK diawali angka SELECT ProductName FROM Products WHERE ProductName LIKE '[^0-9]%'; -- Mencari diskon yang benar-benar mengandung tanda persen (%) SELECT PromoCode FROM Promotions WHERE PromoCode LIKE '%50!%%' ESCAPE '!'; -- Expected: mencocokkan teks yang mengandung literal '50%'

Selain wildcard umum persen (%) untuk mewakili sejumlah karakter apa pun dan underscore (_) untuk mewakili tepat satu karakter, LIKE juga mendukung wildcard kurung siku yang mencocokkan satu karakter dari sekumpulan karakter tertentu, seperti [ABC] yang berarti satu karakter A, B, atau C saja. Menambahkan tanda sisipan (^) tepat setelah kurung buka, seperti [^0-9], membalik makna menjadi 'satu karakter apa pun selain yang disebutkan'.

Masalah muncul ketika karakter yang ingin dicari justru adalah karakter wildcard itu sendiri, misalnya mencari kode promo yang secara literal mengandung tanda persen. Klausa ESCAPE memungkinkan penentuan satu karakter sebagai penanda escape, sehingga wildcard yang didahului karakter tersebut diperlakukan sebagai karakter biasa, bukan sebagai wildcard aktif.

Pola pencarian dengan wildcard di awal string, seperti LIKE '%Laptop%', tidak dapat memanfaatkan index standar secara efisien karena SQL Server tidak bisa menentukan titik awal pencarian pada struktur index B-tree, sehingga mesin database terpaksa memeriksa seluruh baris satu per satu; untuk kebutuhan pencarian teks bebas pada table besar, Full-Text Search biasanya menjadi pilihan yang jauh lebih efisien.

Dampak Leading Wildcard pada LIKE terhadap Penggunaan Indeks

Perbandingan rencana eksekusi LIKE dengan dan tanpa leading wildcard

-- Pola dengan wildcard di awal: tidak bisa memakai Index Seek SELECT NamaProduk FROM dbo.Produk WHERE NamaProduk LIKE '%Laptop%'; -- Execution plan: Index Scan (atau Table Scan) pada seluruh baris -- Pola tanpa wildcard di awal: bisa memakai Index Seek jika ada indeks SELECT NamaProduk FROM dbo.Produk WHERE NamaProduk LIKE 'Laptop%'; -- Execution plan: Index Seek pada IX_Produk_NamaProduk, jauh lebih cepat -- Hasil keduanya bisa sama persis datanya, namun cara SQL Server -- mencari baris di belakang layar sangat berbeda performanya

Indeks non-clustered pada SQL Server disusun berdasarkan urutan karakter dari kiri ke kanan, mirip seperti daftar nama pada buku telepon yang diurutkan berdasarkan huruf pertama. Ketika pola LIKE dimulai dengan karakter pasti seperti 'Laptop%', SQL Server dapat langsung melompat ke posisi yang relevan dalam struktur B-Tree indeks memakai Index Seek, karena tahu persis rentang nilai yang harus dicari.

Sebaliknya, pola yang diawali wildcard seperti '%Laptop%' atau '%Laptop' membuat SQL Server tidak dapat menentukan titik awal pencarian pada struktur indeks, karena karakter yang cocok bisa berada di posisi mana saja dalam string. Akibatnya, optimizer terpaksa memindai seluruh baris table atau seluruh halaman indeks (Index Scan atau Table Scan) dan mencocokkan pola pada setiap baris satu per satu, yang pada table besar dapat menyebabkan penurunan performa signifikan.

Ketika kebutuhan pencarian memang mengharuskan pencocokan substring di tengah atau akhir teks, seperti fitur pencarian produk bebas, solusi yang lebih tepat adalah memakai Full-Text Search yang dirancang khusus SQL Server untuk pencarian teks, karena memanfaatkan indeks full-text yang berbeda struktur dari B-Tree biasa dan jauh lebih efisien untuk pola pencarian semacam ini dibanding mengandalkan LIKE dengan leading wildcard pada kolom besar, terutama ketika jumlah baris pada table sudah mencapai jutaan.

Mencari Posisi Substring dengan CHARINDEX sebagai Alternatif LIKE

CHARINDEX mencari posisi karakter

-- Mencari posisi tanda '@' pada alamat email SELECT Email, CHARINDEX('@', Email) AS PosisiAt FROM dbo.Pelanggan; -- Memotong bagian domain email memakai CHARINDEX dan SUBSTRING SELECT Email, SUBSTRING(Email, CHARINDEX('@', Email) + 1, LEN(Email)) AS Domain FROM dbo.Pelanggan; -- Hasil: budi@gmail.com -> PosisiAt: 5, Domain: gmail.com

CHARINDEX mengembalikan posisi numerik kemunculan pertama suatu substring di dalam string yang lebih besar, berbeda dari LIKE yang hanya memberi jawaban benar atau salah tanpa informasi posisi. Kombinasi CHARINDEX dengan SUBSTRING memungkinkan pengambilan bagian tertentu dari sebuah string berdasarkan posisi karakter penanda, seperti memisahkan bagian domain dari alamat email berdasarkan posisi tanda '@'.

Pendekatan ini lebih fleksibel dibanding LIKE ketika kebutuhannya bukan sekadar memfilter baris yang cocok pola tertentu, melainkan mengekstrak dan mengolah bagian dari teks tersebut untuk ditampilkan atau diolah lebih lanjut. CHARINDEX mengembalikan nilai 0 ketika substring yang dicari tidak ditemukan sama sekali, sehingga penting diperiksa dengan kondisi tambahan sebelum nilai tersebut dipakai sebagai argumen posisi pada SUBSTRING agar tidak menghasilkan error.

Kesalahan Umum yang Sering Terjadi

Memakai leading wildcard pada tabel besar tanpa menyadari dampaknya

Pola seperti '%keyword%' pada tabel jutaan baris bisa membuat query jauh lebih lambat dibanding yang terlihat sepele, karena memaksa table scan penuh setiap kali dijalankan.

Mengasumsikan LIKE selalu case-insensitive di semua server

Perilaku ini bergantung pada collation yang dikonfigurasi, dan asumsi yang salah bisa menyebabkan fitur pencarian berfungsi berbeda antara environment development dan produksi.

Kapan Pendekatan Ini Tidak Cocok Dipakai

LIKE dengan wildcard di kedua sisi tetap valid dan mudah ditulis untuk kebutuhan pencarian sederhana pada tabel kecil atau menengah, namun begitu volume data dan frekuensi pencarian meningkat signifikan (misalnya fitur pencarian utama sebuah aplikasi e-commerce), investasi menyiapkan Full-Text Search atau mesin pencari terpisah akan jauh lebih sepadan dibanding terus mengandalkan LIKE.

Ringkasan

LIKE sangat praktis untuk pencarian teks sederhana, tapi perlu diwaspadai penggunaan leading wildcard pada table besar karena bisa membuat query menjadi lambat akibat table scan penuh.

Mengenali kapan LIKE sudah tidak lagi cukup dan saatnya beralih ke Full-Text Search adalah tanda kematangan dalam merancang fitur pencarian pada aplikasi berskala produksi.

Seri Belajar SQL Server:

← Sebelumnya: Menghapus Duplikasi dengan DISTINCT

→ Selanjutnya: Filtering Rentang Data dengan BETWEEN dan IN