Merhaba arkadaşlar, bugün Laravel projelerimizde sık sık göz ardı ettiğimiz ama performansı kökten etkileyen bir konudan bahsedeceğim: Database Indexing. Özellikle tablo büyüdükçe, "Neden bu sorgu bu kadar yavaş?" sorusunun cevabı çoğu zaman doğru index'lerin olmaması ya da yanlış index'lerin olmasıdır. İşte benim bu konuda edindiğim tecrübeler ve başıma gelen bir can sıkıcı örnek.
Karşılaştığım Sorun: Sonsuz Süren Sipariş Raporu
Bir e-ticaret projesinde, admin panelindeki "son 30 günlük siparişleri filtrele" raporu, veri arttıkça inanılmaz yavaşlamaya başladı. Sorgu 10-15 saniyeyi buluyordu ve bu kabul edilemezdi. EXPLAIN analizi yaptığımda, tam da tahmin ettiğim şeyle karşılaştım: full table scan. Yani veritabanı, milyonlarca kaydın tamamını tarıyordu sadece birkaç bin kayıt getirmek için.
Index Stratejimi Nasıl Belirliyorum?
Benim için altın kural şu: SORGULARINA BAK, INDEX'İNİ ONLARA GÖRE OLUŞTUR. Rastgele alanlara index atmak, yazma performansını düşürmekten başka işe yaramaz. İşte adımlarım:
1. Slow Query Log'u Aç: Laravel'de bunu `DB::listen` ile yakalayabilirsin. Hangi sorguların yavaş çalıştığını bul.
2. EXPLAIN'i Kullan: Yavaş sorguları phpMyAdmin, HeidiSQL ya da doğrudan Artisan tinker ile `EXPLAIN` analizine tabi tut. "type" sütunundaki `ALL` (tam tarama) ibaresi canavarı gösterir.
3. WHERE, ORDER BY, JOIN ve GROUP BY'ı İncele: Index'lenecek sütunları belirlemek için bu clause'lar anahtarımızdır.
Doğru Index'i Oluşturma ve Migration Örneği
Sorunlu sipariş raporu sorgum şuna benziyordu:
Burada `status` ve `created_at` üzerinde bir bileşik index (composite index) işimi görecekti. Laravel migration'da nasıl oluştururuz?
Önemli Not: Bileşik index'lerde sütun sırası HAYATİ ÖNEM TAŞIR. Index `(status, created_at)` şeklindeyken, `WHERE status = ... AND created_at = ...` sorgusu mükemmel çalışır. Ancak `WHERE created_at = ...` sorgusu bu index'i verimli kullanamaz. Sıralama önemli!
Yanlış Index'in Performans Felaketi: Canlı Örnek
İşte başıma gelen gerçek bir hikaye. Hızlı olsun diye, `users` tablosundaki neredeyse her sütuna ayrı ayrı index eklemiştim. `email`, `phone`, `status`, `city`... Gün geldi, kullanıcı kayıt işlemi (INSERT) ve profil güncelleme (UPDATE) işlemleri anormal yavaşladı.
Sebebi şuydu: Her index, tabloya yazılan her yeni kayıt veya güncellenen her kayıt için ekstra yük demek. Veritabanı, veriyi yazdıktan sonra tüm bu index yapılarını da güncellemek zorunda. Gereksiz index'ler, yazma performansını düşürdü, disk alanını şişirdi ve hatta bazen query optimizer'ın yanlış index'i seçmesine neden olup okuma performansını bile olumsuz etkiledi.
Çözümüm: Kullanılmayan index'leri tespit etmek için veritabanı sistem tablolarını (information_schema) sorguladım ve sadece gerçekten sorgularda kullanılan index'leri bırakıp, diğerlerini `$table->dropIndex(...)` ile kaldırdım. Anında yazma performansı düzeldi.
Sonuç ve Özet
Özetle, Laravel'de index stratejisi savurganlık değil, akıllıca yatırım işidir.
Sık kullanılan `WHERE`, `ORDER BY`, `JOIN` sütunlarını index'le.
Bileşik index'lerde sütun sıralamasını sorguna göre belirle.
Her index'in bir bakım maliyeti olduğunu unutma. Gereksiz index'leri temizle.
Migration'larını version control'de tut ki, index değişiklikleri takip edilebilsin.
Siz Laravel projelerinizde index optimizasyonu için hangi araçları kullanıyorsunuz? Hiç yanlış bir index'in başınızı ağrıttığı oldu mu? Yorumlarda deneyimlerinizi paylaşın!
Bir e-ticaret projesinde, admin panelindeki "son 30 günlük siparişleri filtrele" raporu, veri arttıkça inanılmaz yavaşlamaya başladı. Sorgu 10-15 saniyeyi buluyordu ve bu kabul edilemezdi. EXPLAIN analizi yaptığımda, tam da tahmin ettiğim şeyle karşılaştım: full table scan. Yani veritabanı, milyonlarca kaydın tamamını tarıyordu sadece birkaç bin kayıt getirmek için.
Benim için altın kural şu: SORGULARINA BAK, INDEX'İNİ ONLARA GÖRE OLUŞTUR. Rastgele alanlara index atmak, yazma performansını düşürmekten başka işe yaramaz. İşte adımlarım:
1. Slow Query Log'u Aç: Laravel'de bunu `DB::listen` ile yakalayabilirsin. Hangi sorguların yavaş çalıştığını bul.
2. EXPLAIN'i Kullan: Yavaş sorguları phpMyAdmin, HeidiSQL ya da doğrudan Artisan tinker ile `EXPLAIN` analizine tabi tut. "type" sütunundaki `ALL` (tam tarama) ibaresi canavarı gösterir.
3. WHERE, ORDER BY, JOIN ve GROUP BY'ı İncele: Index'lenecek sütunları belirlemek için bu clause'lar anahtarımızdır.
Sorunlu sipariş raporu sorgum şuna benziyordu:
SQL:
SELECT FROM orders WHERE status = 'shipped' AND created_at BETWEEN '2023-10-01' AND '2023-10-30' ORDER BY created_at DESC;
Burada `status` ve `created_at` üzerinde bir bileşik index (composite index) işimi görecekti. Laravel migration'da nasıl oluştururuz?
PHP:
<?php
// Migration dosyası içinde
public function up()
{
Schema::table('orders', function (Blueprint $table) {
// Yanlış: Sadece tek bir alana index
// $table->index('status');
// $table->index('created_at');
// Doğru: Sorgumuzdaki filtrelemeye uygun bileşik index
$table->index(['status', 'created_at']);
});
}
public function down()
{
Schema::table('orders', function (Blueprint $table) {
$table->dropIndex(['status', 'created_at']);
});
}
Önemli Not: Bileşik index'lerde sütun sırası HAYATİ ÖNEM TAŞIR. Index `(status, created_at)` şeklindeyken, `WHERE status = ... AND created_at = ...` sorgusu mükemmel çalışır. Ancak `WHERE created_at = ...` sorgusu bu index'i verimli kullanamaz. Sıralama önemli!
İşte başıma gelen gerçek bir hikaye. Hızlı olsun diye, `users` tablosundaki neredeyse her sütuna ayrı ayrı index eklemiştim. `email`, `phone`, `status`, `city`... Gün geldi, kullanıcı kayıt işlemi (INSERT) ve profil güncelleme (UPDATE) işlemleri anormal yavaşladı.
Sebebi şuydu: Her index, tabloya yazılan her yeni kayıt veya güncellenen her kayıt için ekstra yük demek. Veritabanı, veriyi yazdıktan sonra tüm bu index yapılarını da güncellemek zorunda. Gereksiz index'ler, yazma performansını düşürdü, disk alanını şişirdi ve hatta bazen query optimizer'ın yanlış index'i seçmesine neden olup okuma performansını bile olumsuz etkiledi.
Çözümüm: Kullanılmayan index'leri tespit etmek için veritabanı sistem tablolarını (information_schema) sorguladım ve sadece gerçekten sorgularda kullanılan index'leri bırakıp, diğerlerini `$table->dropIndex(...)` ile kaldırdım. Anında yazma performansı düzeldi.
Özetle, Laravel'de index stratejisi savurganlık değil, akıllıca yatırım işidir.
Sık kullanılan `WHERE`, `ORDER BY`, `JOIN` sütunlarını index'le.
Bileşik index'lerde sütun sıralamasını sorguna göre belirle.
Her index'in bir bakım maliyeti olduğunu unutma. Gereksiz index'leri temizle.
Migration'larını version control'de tut ki, index değişiklikleri takip edilebilsin.
Siz Laravel projelerinizde index optimizasyonu için hangi araçları kullanıyorsunuz? Hiç yanlış bir index'in başınızı ağrıttığı oldu mu? Yorumlarda deneyimlerinizi paylaşın!