MariaDB ve MySQL’de LIKE Operatörü ile Metin Arama Sorguları
Veritabanı yönetiminde en sık ihtiyaç duyulan işlemlerden biri, tablo içindeki verileri belirli bir pattern’e göre filtrelemektir. Tam eşleşme yerine kısmi eşleşme aradığınızda, yani “şununla başlayan”, “şunu içeren” veya “şununla biten” gibi sorgular yazmak istediğinizde LIKE operatörü devreye girer. MySQL ve MariaDB’de LIKE, özellikle kullanıcı arama sistemleri, log filtreleme, ürün katalogları ve içerik yönetim sistemlerinde günlük olarak kullandığınız bir yapıdır. Bu yazıda LIKE operatörünü her açıdan ele alacak, gerçek dünya senaryolarıyla pekiştireceğiz.
LIKE Operatörü Nedir ve Nasıl Çalışır?
LIKE operatörü, WHERE koşulunda metin sütunlarını joker karakterlerle karşılaştırmak için kullanılır. İki temel joker karakter vardır:
- %: Sıfır veya daha fazla herhangi bir karakteri temsil eder
- _: Tam olarak bir karakteri temsil eder
Bu iki karakter kombinasyonuyla oldukça esnek arama sorguları yazabilirsiniz. Sözdizimi son derece basittir:
SELECT kolon_adi FROM tablo_adi WHERE kolon_adi LIKE 'pattern';
MySQL ve MariaDB’de LIKE operatörü varsayılan olarak büyük/küçük harf duyarsızdır (case-insensitive), yani LIKE 'admin' ile LIKE 'ADMIN' aynı sonucu döndürür. Bu davranış sütunun collation ayarına bağlıdır. Eğer büyük/küçük harf duyarlı arama yapmak istiyorsanız BINARY anahtar kelimesini kullanmanız gerekir, bunu ilerleyen bölümlerde göreceğiz.
Temel Kullanım Örnekleri
% Joker Karakteri ile Arama
En yaygın senaryo ile başlayalım. Diyelim ki bir e-ticaret sitesinin veritabanında ürün tablosu var ve “telefon” kelimesini içeren tüm ürünleri bulmak istiyorsunuz:
-- "telefon" içeren tüm ürünler
SELECT urun_id, urun_adi, fiyat FROM urunler
WHERE urun_adi LIKE '%telefon%';
-- Sonuç örneği:
-- Samsung Galaxy Telefon Kılıfı
-- iPhone Telefon Tutucu
-- Telefon Şarj Kablosu
-- Akıllı Telefon Ekran Koruyucu
Burada %telefon% pattern’i, “telefon” kelimesinin önünde ve arkasında herhangi bir karakter dizisi olabileceği anlamına gelir. Sadece başından aramak veya sadece sonundan aramak isterseniz:
-- "Samsung" ile başlayan ürünler
SELECT urun_adi, kategori FROM urunler
WHERE urun_adi LIKE 'Samsung%';
-- ".jpg" ile biten dosya yolu kayıtları
SELECT dosya_adi, yukleme_tarihi FROM medya_dosyalari
WHERE dosya_yolu LIKE '%.jpg';
_ Joker Karakteri ile Tam Uzunluk Araması
Alt çizgi karakteri daha spesifik senaryolarda işe yarar. Örneğin, ülke kodu gibi sabit uzunlukta verilerde veya belirli bir format kontrolünde kullanabilirsiniz:
-- TR ile başlayan, ardından tam 8 karakter gelen telefon numaraları
SELECT musteri_adi, telefon FROM musteriler
WHERE telefon LIKE 'TR________';
-- 3 karakterli ülke kodları
SELECT ulke_kodu, ulke_adi FROM ulkeler
WHERE ulke_kodu LIKE '___';
-- "A" ile başlayan 5 harfli ürün kodları
SELECT urun_kodu, urun_adi FROM urunler
WHERE urun_kodu LIKE 'A____';
Gerçek Dünya Senaryoları
Senaryo 1: Kullanıcı Arama Sistemi
Bir CRM uygulamasında müşteri adına göre arama yapmanız gerekiyor. Kullanıcı arama kutusuna “ahmet” yazdığında, “Ahmet”, “Mehmet”, “Ahmet Ali” gibi sonuçları getirmek istiyorsunuz:
-- Kullanıcı girişine göre dinamik arama (PHP/uygulama tarafında
-- parametreli sorgu kullanmayı unutmayın!)
SELECT
musteri_id,
ad,
soyad,
email,
telefon
FROM musteriler
WHERE
ad LIKE '%ahmet%'
OR soyad LIKE '%ahmet%'
OR CONCAT(ad, ' ', soyad) LIKE '%ahmet%'
ORDER BY soyad, ad;
Bu sorguyu production ortamında kullanırken mutlaka parametreli sorgular kullanın. Ham string birleştirmesiyle SQL injection açığı yaratabilirsiniz.
Senaryo 2: Log Dosyası Analizi
Uygulama loglarını veritabanında saklıyorsanız (ki bu yaygın bir pratiktir), belirli hata mesajlarını filtrelemek için LIKE son derece kullanışlıdır:
-- Son 24 saatte "connection refused" içeren log kayıtları
SELECT
log_id,
log_seviyesi,
log_mesaji,
sunucu_ip,
olusturma_zamani
FROM uygulama_loglari
WHERE
log_mesaji LIKE '%connection refused%'
AND olusturma_zamani >= NOW() - INTERVAL 24 HOUR
ORDER BY olusturma_zamani DESC;
-- ERROR ile başlayan tüm kritik logları say
SELECT
DATE(olusturma_zamani) AS tarih,
COUNT(*) AS hata_sayisi
FROM uygulama_loglari
WHERE log_mesaji LIKE 'ERROR%'
GROUP BY DATE(olusturma_zamani)
ORDER BY tarih DESC
LIMIT 30;
Senaryo 3: E-posta Domain Filtreleme
Belirli bir domain’e sahip kullanıcıları bulmak, bulk e-posta operasyonlarında veya domain bazlı kısıtlamalar uygularken çok işe yarar:
-- Gmail kullanıcılarını bul
SELECT kullanici_adi, email, kayit_tarihi
FROM kullanicilar
WHERE email LIKE '%@gmail.com';
-- Kurumsal e-posta kullanmayan kullanıcıları bul
-- (ücretsiz servisler listesi)
SELECT kullanici_adi, email FROM kullanicilar
WHERE
email LIKE '%@gmail.com'
OR email LIKE '%@hotmail.com'
OR email LIKE '%@yahoo.com'
OR email LIKE '%@outlook.com';
-- Belirli bir şirketin tüm çalışanları
SELECT ad, soyad, email, departman
FROM personel
WHERE email LIKE '%@sirketadi.com.tr'
ORDER BY departman, soyad;
LIKE ile NOT LIKE Kullanımı
LIKE’ın tersini almak için NOT LIKE kullanırsınız. Bu özellikle belirli pattern’leri dışlamak istediğinizde işe yarar:
-- Test kullanıcılarını dışla
SELECT kullanici_adi, email, son_giris
FROM kullanicilar
WHERE
kullanici_adi NOT LIKE '%test%'
AND kullanici_adi NOT LIKE '%demo%'
AND email NOT LIKE '%@test.com'
ORDER BY son_giris DESC;
-- Belirli bir prefix ile başlamayan ürün kodlarını bul
SELECT urun_kodu, urun_adi, stok_miktari
FROM urunler
WHERE urun_kodu NOT LIKE 'ARCH_%'
AND stok_miktari > 0;
BINARY ile Case-Sensitive Arama
Varsayılan olarak case-insensitive olan LIKE’ı büyük/küçük harf duyarlı hale getirmek için BINARY anahtar kelimesini kullanırsınız:
-- Case-sensitive arama: sadece küçük harfli "admin" bulur
SELECT kullanici_adi, email FROM kullanicilar
WHERE kullanici_adi LIKE BINARY 'admin%';
-- "Admin", "ADMIN" gibi varyasyonları dışarıda bırakır
-- Sadece "admin", "administrator" gibi küçük harfle başlayanları getirir
-- Karşılaştırma: case-insensitive vs sensitive
-- Bu sorgu "Admin", "ADMIN", "admin" hepsini getirir:
SELECT kullanici_adi FROM kullanicilar
WHERE kullanici_adi LIKE 'admin%';
-- Bu sorgu sadece "admin" ile başlayanları getirir:
SELECT kullanici_adi FROM kullanicilar
WHERE kullanici_adi LIKE BINARY 'admin%';
Joker Karakterlerin Escape Edilmesi
Peki ya arama yapmak istediğiniz metinde % veya _ karakteri varsa? Örneğin “%50 indirim” ifadesini içeren kayıtları arıyorsunuz. Bu durumda ESCAPE anahtar kelimesini kullanmanız gerekir:
-- Yüzde işareti içeren kampanya isimlerini ara
SELECT kampanya_adi, baslangic_tarihi, bitis_tarihi
FROM kampanyalar
WHERE kampanya_adi LIKE '%%%' ESCAPE '';
-- Alt çizgi içeren ürün kodlarını ara
-- Örneğin "ABC_123" formatındaki kodları bulmak için
SELECT urun_kodu, urun_adi FROM urunler
WHERE urun_kodu LIKE '%_%' ESCAPE '';
-- Özel escape karakteri belirleyerek kullanım
SELECT aciklama FROM notlar
WHERE aciklama LIKE '%!%%' ESCAPE '!';
LIKE ile JOIN Kullanımı
LIKE’ı JOIN sorgularıyla birleştirdiğinizde daha güçlü sorgular yazabilirsiniz:
-- Kategori adı "elektronik" içeren kategorilerdeki ürünleri getir
SELECT
u.urun_id,
u.urun_adi,
u.fiyat,
k.kategori_adi,
m.marka_adi
FROM urunler u
INNER JOIN kategoriler k ON u.kategori_id = k.kategori_id
INNER JOIN markalar m ON u.marka_id = m.marka_id
WHERE
k.kategori_adi LIKE '%elektronik%'
AND u.aktif = 1
ORDER BY u.fiyat ASC;
-- İstanbul'daki müşterilerin siparişlerini bul
SELECT
s.siparis_id,
CONCAT(m.ad, ' ', m.soyad) AS musteri_adi,
m.sehir,
s.toplam_tutar,
s.siparis_tarihi
FROM siparisler s
INNER JOIN musteriler m ON s.musteri_id = m.musteri_id
WHERE
m.adres LIKE '%İstanbul%'
AND s.siparis_tarihi >= '2024-01-01'
ORDER BY s.siparis_tarihi DESC;
Performans Konuları ve LIKE Optimizasyonu
Bu kısım birçok sysadmin ve DBA’in gözden kaçırdığı kritik bir noktadır. LIKE operatörü yanlış kullanıldığında index’leri bypass eder ve full table scan yapar. Bunu anlamak production performansı için hayati önem taşır.
Index Kullanımı Açısından LIKE Pattern’leri
LIKE 'samsung%': Başından sabit bir string ile başlayan pattern, index kullanır (range scan). En verimli kullanım budur.LIKE '%samsung%': Başında % olan pattern, index kullanamaz (full table scan). Büyük tablolarda ciddi performans sorununa yol açar.LIKE '%samsung': Başında % olan pattern, index kullanamaz.
Bunu EXPLAIN ile doğrulayabilirsiniz:
-- Index kullanımını kontrol et
EXPLAIN SELECT urun_adi, fiyat FROM urunler
WHERE urun_adi LIKE 'Samsung%';
-- Full table scan'i tespit et
EXPLAIN SELECT urun_adi, fiyat FROM urunler
WHERE urun_adi LIKE '%Samsung%';
-- urun_adi sütununa index ekle (başından arama için faydalı)
ALTER TABLE urunler ADD INDEX idx_urun_adi (urun_adi);
-- Büyük tablolarda LIKE '%...%' için FULLTEXT index kullan
ALTER TABLE urunler ADD FULLTEXT INDEX ft_urun_adi (urun_adi);
-- FULLTEXT ile MATCH...AGAINST kullanımı (LIKE yerine)
SELECT urun_adi, fiyat FROM urunler
WHERE MATCH(urun_adi) AGAINST('samsung' IN BOOLEAN MODE);
LIKE Sorgularında Pratik Performans İpuçları
- Başından arama yapabiliyorsanız
LIKE 'prefix%formatını tercih edin, bu index’i kullanır. - Orta veya sondaki eşleşmeler için FULLTEXT index düşünün.
- Çok sık çalışan büyük tablo sorguları için sonuçları cache’leyin (Redis/Memcached).
- Küçük tablolarda (birkaç bin satır) full table scan genellikle sorun değildir.
WHERE LIKEkoşulunu diğer indeksli koşullarla birleştirin, böylece önce indeksli filtreleme yapılır, LIKE az sayıda satıra uygulanır.
-- Kötü performans: tüm tabloyu tarar
SELECT * FROM siparisler WHERE notlar LIKE '%acil%';
-- İyi performans: önce tarih filtresi (indeksli) uygulanır,
-- sonra LIKE az sayıda satıra uygulanır
SELECT * FROM siparisler
WHERE
siparis_tarihi >= '2024-01-01'
AND musteri_id = 12345
AND notlar LIKE '%acil%';
LIKE ile Aggregate Fonksiyonlar
LIKE’ı COUNT, SUM gibi aggregate fonksiyonlarla birleştirerek istatistiksel sorgular da yazabilirsiniz:
-- Domain bazlı kullanıcı sayısı raporu
SELECT
SUBSTRING_INDEX(email, '@', -1) AS domain,
COUNT(*) AS kullanici_sayisi
FROM kullanicilar
WHERE
email LIKE '%@%.%'
AND aktif = 1
GROUP BY SUBSTRING_INDEX(email, '@', -1)
HAVING kullanici_sayisi > 10
ORDER BY kullanici_sayisi DESC;
-- "İade" içeren sipariş notlarının toplam tutarı
SELECT
COUNT(*) AS iade_siparis_sayisi,
SUM(toplam_tutar) AS toplam_iade_tutari,
AVG(toplam_tutar) AS ortalama_iade_tutari
FROM siparisler
WHERE
siparis_notu LIKE '%iade%'
AND siparis_tarihi >= DATE_SUB(NOW(), INTERVAL 3 MONTH);
Çoklu Pattern ile Gelişmiş Arama
Birden fazla LIKE koşulunu OR/AND ile birleştirerek karmaşık arama senaryoları oluşturabilirsiniz:
-- Çoklu anahtar kelime araması
SELECT
icerik_id,
baslik,
yazar,
yayin_tarihi
FROM icerikler
WHERE
(
baslik LIKE '%mysql%'
OR baslik LIKE '%mariadb%'
OR icerik LIKE '%veritabani%'
OR etiketler LIKE '%sql%'
)
AND durum = 'yayinda'
AND yayin_tarihi >= '2023-01-01'
ORDER BY yayin_tarihi DESC
LIMIT 20;
-- Hem belli bir pattern içeren hem de içermeyen kayıtlar
SELECT urun_kodu, urun_adi, kategori
FROM urunler
WHERE
urun_adi LIKE '%kablosuz%'
AND urun_adi NOT LIKE '%kılıf%'
AND urun_adi NOT LIKE '%aksesuar%'
AND stok_miktari > 0;
MariaDB’ye Özgü: REGEXP ile Karşılaştırma
Bazı durumlarda LIKE yetmez ve daha güçlü pattern matching’e ihtiyaç duyarsınız. MariaDB ve MySQL’de REGEXP (veya RLIKE) operatörü bu ihtiyacı karşılar:
-- LIKE ile: "05" ile başlayan telefon numaraları
SELECT musteri_adi, telefon FROM musteriler
WHERE telefon LIKE '05%';
-- REGEXP ile: daha esnek telefon format kontrolü
SELECT musteri_adi, telefon FROM musteriler
WHERE telefon REGEXP '^0[0-9]{10}$';
-- Geçerli e-posta format kontrolü (basit)
SELECT email FROM kullanicilar
WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$';
REGEXP LIKE’tan daha güçlü olsa da genellikle daha yavaştır. Basit pattern’ler için LIKE tercih edilmelidir.
Güvenlik: SQL Injection ve LIKE
LIKE sorgularında SQL injection riski özellikle önemlidir. Uygulamanızda kullanıcıdan aldığınız girdiyi doğrudan sorguya koymayın:
-- YANLIS yöntem (PHP örneği ile açıklama için SQL olarak gösteriyoruz):
-- WHERE urun_adi LIKE '%' + kullanici_girdisi + '%'
-- Kullanıcı "%" veya "_" girerse beklenmedik sonuçlar alırsınız
-- Kullanıcı "'; DROP TABLE urunler; --" girerse felaket olur
-- DOGRU yöntem: Uygulama tarafında her zaman parametreli sorgu kullanın
-- PHP PDO örneği:
-- $stmt = $pdo->prepare("SELECT * FROM urunler WHERE urun_adi LIKE ?");
-- $arama = '%' . $kullanici_girdisi . '%';
-- $stmt->execute([$arama]);
-- MariaDB/MySQL stored procedure içinde güvenli kullanım:
DELIMITER //
CREATE PROCEDURE UrunAra(IN p_arama VARCHAR(100))
BEGIN
SET @sorgu = CONCAT('%', p_arama, '%');
SELECT urun_id, urun_adi, fiyat
FROM urunler
WHERE urun_adi LIKE @sorgu;
END //
DELIMITER ;
-- Çağırma:
CALL UrunAra('telefon');
Sonuç
LIKE operatörü, MySQL ve MariaDB’de metin aramaları için vazgeçilmez bir araçtır. % ve _ joker karakterleriyle oldukça esnek pattern’ler oluşturabilir, NOT LIKE ile ters filtreleme yapabilir, BINARY ile case-sensitive aramaya geçebilirsiniz.
Ancak en kritik nokta performanstır. Başında % bulunan pattern’ler index kullanamaz ve büyük tablolarda ciddi yavaşlamalara neden olur. Production ortamında sık çalışan ve büyük tablolara dokunan LIKE '%metin%' sorgularınız varsa FULLTEXT index veya Elasticsearch gibi arama motorlarına geçmeyi mutlaka değerlendirin.
Günlük yönetim işlerinizde LIKE’ı bilinçli kullandığınızda, kullanıcı aramaları, log analizleri, veri temizleme ve raporlama görevlerinde hem yazmaya hem de anlamaya kolay, güçlü sorgular elde edersiniz. EXPLAIN ile sorgu planınızı her zaman kontrol etmeyi ve uygulama tarafında parametreli sorguları kullanmayı ihmal etmeyin.
