Merhaba arkadaşlar, bugün sizlere özellikle forumlar, bloglar veya içerik yönetim sistemlerinde sıkça karşılaştığımız bir performans problemini ve onun kurşun geçirmez çözümünü anlatacağım: Metin aramalarını hızlandırmak. "LIKE '%aranan%'" sorguları tablonuz büyüdükçe sunucunuzu dizlerinin üzerine çökertebilir. Neyse ki MySQL'in içinde bu iş için özel olarak tasarlanmış çok güçlü bir silah var: FULLTEXT Index. Bu rehberde, bu indeksi nasıl oluşturacağımızı, nasıl kullanacağımızı ve ayarlarla nasıl ince ayar yapacağımızı adım adım işleyeceğiz.
FULLTEXT Index Nedir ve Ne Zaman Kullanılır?
FULLTEXT index, bir tablodaki metin sütunları (VARCHAR, TEXT) üzerinde, kelime bazlı hızlı arama yapabilmek için oluşturulan özel bir indeks türüdür. Geleneksel B-tree indeksler "LIKE 'kelime%'" gibi ön ek aramalarında iyidir, ancak "LIKE '%kelime%'" veya birden fazla kelime içeren karmaşık aramalarda tamamen etkisiz kalır. İşte tam bu noktada FULLTEXT devreye girer.
Benim sunucularda genelde, kullanıcı mesajlarının, makale içeriklerinin veya ürün açıklamalarının arandığı her yerde bu yönteme başvururum. Performans farkı inanılmazdır.
FULLTEXT Index Oluşturma ve Temel Kullanım
Öncelikle, üzerinde arama yapmak istediğimiz bir tablomuz ve sütunumuz olduğunu varsayalım. Diyelim ki `makaleler` adında bir tablomuz ve `baslik` ile `icerik` alanlarında arama yapmak istiyoruz.
İlk adım, mevcut tablomuza bir FULLTEXT indeksi eklemek. Şu ayara çok dikkat etmelisiniz: InnoDB motoru için MySQL 5.6 ve sonrası FULLTEXT'i destekler. Eski MyISAM tablolarında da çalışır ama InnoDB kullanmanızı şiddetle tavsiye ederim.
İndeksi oluşturduk. Peki nasıl arama yapacağız? `MATCH() ... AGAINST()` yapısını kullanacağız.
Bu sorgu, `baslik` ve `icerik` alanlarında "veritabanı" ve "optimizasyonu" kelimelerini içeren ve bu kelimelere göre bir ilgi puanı (relevance score) hesaplanmış kayıtları getirecektir. Sıralama yapmak isterseniz:
İleri Seviye: Boolean Modu ve Stopwords
Doğal dil modu güzel ama bazen daha fazla kontrol istersiniz. Örneğin, bir kelimenin kesinlikle olmasını (+), olmamasını (-) veya alt sorguları () belirlemek isteyebilirsiniz. Boolean mod tam size göre.
Bir diğer kritik konu da "stopwords" yani dilde sık geçtiği için indekslenmeyen kelimeler (ve, veya, bir, gibi). MySQL'in varsayılan bir stopword listesi vardır. Eğer aramalarınızda bu kelimeler önemliyse (örneğin, "ve" bağlacı bir marka adının parçası olabilir), listeyi yönetebilirsiniz. Dosya yolu /usr/share/mysql/stopwords.txt (veya information_schema.INNODB_FT_DEFAULT_STOPWORD) olabilir. Değişiklik yapmak ciddi bir iştir, test ortamında denemeden production'a sürmeyin.
Dikkat Edilmesi Gerekenler ve Optimizasyon İpuçları
1. İndeks Boyutu: FULLTEXT indeksleri, özellikle büyük TEXT alanları üzerinde oluşturulduğunda oldukça büyük yer kaplayabilir. Disk alanınızı gözden geçirin.
2. Minimum Kelime Uzunluğu: Varsayılan olarak, 3 veya 4 karakterden kısa kelimeler indekslenmez (`ft_min_word_len` veya `innodb_ft_min_token_size` ayarı). Bu, "ve", "için" gibi kelimelerin aranmaması anlamına gelir. Bu ayarı değiştirirseniz, indeksi yeniden oluşturmanız (REBUILD) gerekir!
Ayarları değiştirdikten sonra:
3. Sorgu Performansı: `MATCH()` fonksiyonunun içinde indeks tanımlarken kullandığınız sütunların aynı sırada ve hepsini yazın. Aksi takdirde indeks kullanılmaz.
4. MyISAM vs InnoDB: Mümkünse InnoDB kullanın. MyISAM, tablo seviyesinde kilitler ve büyük ölçekli sistemlerde sorun çıkarabilir.
Sonuç ve Öneriler
FULLTEXT index, metin aramalarından mustarip olan her uygulama için bir game-changer'dır. Doğru şekilde uygulandığında, saniyeler süren sorguları milisaniyelere indirebilir. Başlangıçta doğal dil modu ile başlayıp, ihtiyaçlarınız arttıkça Boolean modunun gücünden faydalanabilirsiniz.
Ben genelde, büyük metin alanları için ayrı bir FULLTEXT indeks, başlık gibi kısa alanlar için ise ayrı bir indeks oluşturmayı tercih ederim. Bu, sorgu performansını daha da optimize edebilir.
Peki siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? FULLTEXT ile ilgili yaşadığınız ilginç performans hikayeleriniz veya takıldığınız noktalar var mı? Aşağıya yorum olarak yazarsanız, topluluk olarak çözüm bulabiliriz. Sağlıcakla kalın, kodunuz bol olsun!
FULLTEXT index, bir tablodaki metin sütunları (VARCHAR, TEXT) üzerinde, kelime bazlı hızlı arama yapabilmek için oluşturulan özel bir indeks türüdür. Geleneksel B-tree indeksler "LIKE 'kelime%'" gibi ön ek aramalarında iyidir, ancak "LIKE '%kelime%'" veya birden fazla kelime içeren karmaşık aramalarda tamamen etkisiz kalır. İşte tam bu noktada FULLTEXT devreye girer.
Benim sunucularda genelde, kullanıcı mesajlarının, makale içeriklerinin veya ürün açıklamalarının arandığı her yerde bu yönteme başvururum. Performans farkı inanılmazdır.
Öncelikle, üzerinde arama yapmak istediğimiz bir tablomuz ve sütunumuz olduğunu varsayalım. Diyelim ki `makaleler` adında bir tablomuz ve `baslik` ile `icerik` alanlarında arama yapmak istiyoruz.
İlk adım, mevcut tablomuza bir FULLTEXT indeksi eklemek. Şu ayara çok dikkat etmelisiniz: InnoDB motoru için MySQL 5.6 ve sonrası FULLTEXT'i destekler. Eski MyISAM tablolarında da çalışır ama InnoDB kullanmanızı şiddetle tavsiye ederim.
SQL:
-- Mevcut bir tabloya FULLTEXT indeksi ekleme
ALTER TABLE makaleler ADD FULLTEXT INDEX `ft_idx_baslik_icerik` (`baslik`, `icerik`);
-- Veya tablo oluştururken ekleyebilirsiniz.
CREATE TABLE makaleler (
id INT AUTO_INCREMENT PRIMARY KEY,
baslik VARCHAR(255),
icerik TEXT,
FULLTEXT INDEX `ft_idx_baslik_icerik` (`baslik`, `icerik`)
);
İndeksi oluşturduk. Peki nasıl arama yapacağız? `MATCH() ... AGAINST()` yapısını kullanacağız.
SQL:
-- Doğal dil modunda basit arama
SELECT FROM makaleler
WHERE MATCH(baslik, icerik) AGAINST('veritabanı optimizasyonu' IN NATURAL LANGUAGE MODE);
Bu sorgu, `baslik` ve `icerik` alanlarında "veritabanı" ve "optimizasyonu" kelimelerini içeren ve bu kelimelere göre bir ilgi puanı (relevance score) hesaplanmış kayıtları getirecektir. Sıralama yapmak isterseniz:
SQL:
SELECT id, baslik,
MATCH(baslik, icerik) AGAINST('veritabanı optimizasyonu') AS puan
FROM makaleler
WHERE MATCH(baslik, icerik) AGAINST('veritabanı optimizasyonu')
ORDER BY puan DESC;
Doğal dil modu güzel ama bazen daha fazla kontrol istersiniz. Örneğin, bir kelimenin kesinlikle olmasını (+), olmamasını (-) veya alt sorguları () belirlemek isteyebilirsiniz. Boolean mod tam size göre.
SQL:
-- "optimizasyonu" kelimesi geçsin, "yavaş" kelimesi geçmesin, "MySQL" kelimesi önemli olsun.
SELECT FROM makaleler
WHERE MATCH(baslik, icerik) AGAINST('+optimizasyonu -yavaş MySQL' IN BOOLEAN MODE);
Bir diğer kritik konu da "stopwords" yani dilde sık geçtiği için indekslenmeyen kelimeler (ve, veya, bir, gibi). MySQL'in varsayılan bir stopword listesi vardır. Eğer aramalarınızda bu kelimeler önemliyse (örneğin, "ve" bağlacı bir marka adının parçası olabilir), listeyi yönetebilirsiniz. Dosya yolu /usr/share/mysql/stopwords.txt (veya information_schema.INNODB_FT_DEFAULT_STOPWORD) olabilir. Değişiklik yapmak ciddi bir iştir, test ortamında denemeden production'a sürmeyin.
1. İndeks Boyutu: FULLTEXT indeksleri, özellikle büyük TEXT alanları üzerinde oluşturulduğunda oldukça büyük yer kaplayabilir. Disk alanınızı gözden geçirin.
2. Minimum Kelime Uzunluğu: Varsayılan olarak, 3 veya 4 karakterden kısa kelimeler indekslenmez (`ft_min_word_len` veya `innodb_ft_min_token_size` ayarı). Bu, "ve", "için" gibi kelimelerin aranmaması anlamına gelir. Bu ayarı değiştirirseniz, indeksi yeniden oluşturmanız (REBUILD) gerekir!
INI:
# my.cnf veya my.ini dosyasında
[mysqld]
innodb_ft_min_token_size = 2
ft_min_word_len = 2
SQL:
ALTER TABLE makaleler DROP INDEX ft_idx_baslik_icerik;
ALTER TABLE makaleler ADD FULLTEXT INDEX ft_idx_baslik_icerik (baslik, icerik);
4. MyISAM vs InnoDB: Mümkünse InnoDB kullanın. MyISAM, tablo seviyesinde kilitler ve büyük ölçekli sistemlerde sorun çıkarabilir.
FULLTEXT index, metin aramalarından mustarip olan her uygulama için bir game-changer'dır. Doğru şekilde uygulandığında, saniyeler süren sorguları milisaniyelere indirebilir. Başlangıçta doğal dil modu ile başlayıp, ihtiyaçlarınız arttıkça Boolean modunun gücünden faydalanabilirsiniz.
Ben genelde, büyük metin alanları için ayrı bir FULLTEXT indeks, başlık gibi kısa alanlar için ise ayrı bir indeks oluşturmayı tercih ederim. Bu, sorgu performansını daha da optimize edebilir.
Peki siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? FULLTEXT ile ilgili yaşadığınız ilginç performans hikayeleriniz veya takıldığınız noktalar var mı? Aşağıya yorum olarak yazarsanız, topluluk olarak çözüm bulabiliriz. Sağlıcakla kalın, kodunuz bol olsun!