🚨 İXTİF Site Performans Analizi

📅 Tarih: 2025-11-29 23:15 | 🎯 Site: ixtif.com (Tenant 2) | 👤 Analiz: Claude AI

⚠️ KRİTİK DURUM TESPİT EDİLDİ

Site yüklenme süreleri kabul edilemez seviyede yavaş. Ortalama yüklenme süresi 3-8 saniye arasında değişiyor. Hedef: 1 saniye altı

Ana Sorun: Veritabanı query'leri optimize edilmemiş, index'ler eksik, Response Cache çalışmıyor.

📊 Performans Metrikleri

8.3s
En Yavaş Yüklenme (Homepage)
11.9s
En Kötü Ürün Detay Sayfası
946ms
En Yavaş Query (Shop Products)
422ms
Blog Query (Media Subquery)
4.1s
Thumbmaker İşleme Süresi
17
Homepage'deki Ürün Sayısı
Not: Kabul edilebilir yüklenme süresi: 1 saniye altı. Google PageSpeed Insights'a göre 3 saniyenin üzeri "yavaş" kategorisindedir.

🐌 Tespit Edilen Yavaş Query'ler

1. Shop Products Query - 946.58ms Yüksek Etki

Lokasyon: Homepage - Featured Products Section

SELECT * FROM `shop_products` WHERE `category_id` = 1 AND `is_active` = 1 AND `parent_product_id` IS NULL AND `shop_products`.`deleted_at` IS NULL ORDER BY `sort_order` ASC LIMIT 4

Sorun: Index kullanılmıyor! MySQL, sort_order index'ini kullanıyor ama WHERE koşulları için uygun composite index yok.

EXPLAIN Sonucu: Using where - Full table scan yapılıyor (24 satır taranıyor)

2. Blog Media Exists Subquery - 422.7ms Yüksek Etki

Lokasyon: Homepage - Blog Section (muhtemelen layout'ta)

SELECT * FROM `blogs` WHERE `is_active` = 1 AND (`published_at` IS NULL OR `published_at` <= '2025-11-29 20:12:04') AND EXISTS ( SELECT * FROM `media` WHERE `blogs`.`blog_id` = `media`.`model_id` AND `media`.`model_type` = 'Modules\\Blog\\App\\Models\\Blog' AND `collection_name` IN ('hero', 'featured_image', 'gallery') ) AND `blogs`.`deleted_at` IS NULL ORDER BY `published_at` DESC LIMIT 6

Sorun: Blogs tablosunda hiç index yok! Sadece PRIMARY KEY var. is_active, published_at, deleted_at için index eksik.

Ek Sorun: Media EXISTS subquery her blog için çalışıyor - N+1 problemi!

3. Search Queries Aggregation - 114ms Orta Etki

SELECT query, MAX(slug) as slug, COUNT(*) as search_count FROM `search_queries` WHERE `is_popular` = 1 AND `is_hidden` = 0 GROUP BY `query` ORDER BY `search_count` DESC LIMIT 10

Sorun: GROUP BY ve COUNT(*) hesaplaması yavaş. Muhtemelen index eksik veya materialized view gerekli.

4. Thumbmaker İşleme - 1.8s - 4.1s Yüksek Etki

URL: /thumbmaker?c=1&f=webp&h=300&q=80&src=...

Sorun: Resim işleme on-the-fly yapılıyor. Cache edilmiş thumbnail'ler yok veya cache miss oluyor.

Etki: Homepage'de 17 ürün x her ürün için thumbnail = potansiyel olarak 17+ thumbmaker isteği

📋 Sayfa Bazlı Yüklenme Süreleri

Sayfa Yüklenme Süresi Durum Notlar
Homepage (/) 1.4s - 9.5s Kritik Değişken performans, cache çalışmıyor
Ürün Detay 11.6s - 11.9s Kritik En yavaş sayfa!
Mesafeli Satış 7.1s Kritik Statik içerik bile yavaş
Shop İndex (/shop) 4.1s Kritik Ürün listesi yavaş
Yedek Parça 5.1s Kritik -
Blog 404 4.7s Kritik 404 bile yavaş!

🔍 Kök Neden Analizi

1. Database Index Eksiklikleri

Tespit Edilen Sorunlar:

  • Blogs Tablosu: Sadece PRIMARY KEY var! is_active, published_at, deleted_at için index yok
  • Shop Products: category_id + is_active + deleted_at + sort_order composite index eksik
  • Search Queries: is_popular + is_hidden + query composite index eksik
  • Media: model_id + model_type + collection_name composite index kontrol edilmeli

2. N+1 Query Problemi

Tespit Edilen Sorunlar:

  • Blog query'sinde media EXISTS subquery her blog için tekrar çalışıyor
  • Homepage controller'da with(['category', 'brand', 'media']) var ama thumb() her ürün için ayrı çağrılıyor
  • Currency ilişkisi doğru çözülmüş ama diğer ilişkiler kontrol edilmeli

3. Response Cache Çalışmıyor

Tespit Edilen Sorunlar:

  • .env'de RESPONSE_CACHE_ENABLED=true ama cache'li response dönmüyor
  • Yüklenme süreleri değişken (1.4s - 9.5s) - cache çalışsaydı sabit olurdu
  • Cache temizleme sonrası bile yavaş (2.3s) - query'ler optimize değil

4. Thumbmaker On-The-Fly İşleme

Tespit Edilen Sorunlar:

  • Thumbnail'ler önceden oluşturulmuyor
  • Her istek için resim işleme yapılıyor (1.8s - 4.1s)
  • 17 ürün x her ürün için thumbnail = 17+ thumbmaker isteği
  • WebP dönüşümü her seferinde yapılıyor

✅ Çözüm Önerileri (Öncelik Sırasına Göre)

🔴 1. Kritik: Database Index'lerini Ekle Yüksek Öncelik

Beklenen Kazanç: 946ms → ~50ms (18x hızlanma)

-- Blogs tablosu için composite index CREATE INDEX blogs_active_published_idx ON blogs(is_active, published_at, deleted_at); -- Shop products için optimize composite index CREATE INDEX shop_products_cat_active_parent_sort_idx ON shop_products(category_id, is_active, parent_product_id, deleted_at, sort_order); -- Search queries için composite index CREATE INDEX search_queries_popular_hidden_idx ON search_queries(is_popular, is_hidden, query); -- Media için composite index (varsa kontrol et) CREATE INDEX media_model_collection_idx ON media(model_id, model_type, collection_name);

İşlem: Migration oluştur ve çalıştır. Production'da ALGORITHM=INPLACE kullan (downtime olmaz).

🔴 2. Kritik: Blog Query'sini Optimize Et Yüksek Öncelik

Beklenen Kazanç: 422ms → ~20ms (21x hızlanma)

Strateji: EXISTS subquery yerine LEFT JOIN veya eager loading kullan

// ❌ YAVAŞ (mevcut) Blog::where('is_active', true) ->whereHas('media', function($q) { $q->whereIn('collection_name', ['hero', 'featured_image', 'gallery']); }) ->orderBy('published_at', 'desc') ->limit(6) ->get(); // ✅ HIZLI (öneri) Blog::where('is_active', true) ->with(['media' => function($q) { $q->whereIn('collection_name', ['hero', 'featured_image', 'gallery']); }]) ->orderBy('published_at', 'desc') ->limit(6) ->get() ->filter(function($blog) { return $blog->media->isNotEmpty(); });

Lokasyon: Bu query'nin nerede çağrıldığını bul (muhtemelen layout veya homepage component).

🟡 3. Yüksek: Thumbnail Cache Sistemi Yüksek Öncelik

Beklenen Kazanç: 4.1s → ~50ms (82x hızlanma)

Strateji: Thumbnail'leri önceden oluştur ve cache'le

  • Upload sırasında yaygın boyutlarda (400x400, 300x300 vb.) thumbnail oluştur
  • Thumbmaker cache süresini artır (mevcut cache varsa kontrol et)
  • CDN kullanımını değerlendir (CloudFlare, AWS CloudFront)
  • HTTP Cache header'ları ekle (max-age=31536000 - 1 yıl)

🟡 4. Orta: Response Cache'i Düzelt Orta Öncelik

Beklenen Kazanç: İkinci yükleme: 2.3s → ~100ms (23x hızlanma)

İnceleme Noktaları:

  • Response Cache middleware route'lara eklenmiş mi kontrol et
  • Cache driver (Redis) çalışıyor mu kontrol et
  • Cache-Control header'ları doğru mu kontrol et
  • Authenticated kullanıcılar için cache bypass ediliyor mu kontrol et

🟡 5. Orta: Homepage Ürün Sayısını Azalt Orta Öncelik

Mevcut: 17 ürün (hepsi aynı anda yükleniyor)

Öneri: İlk yükleme: 8 ürün + "Daha Fazla Yükle" butonu (lazy loading)

  • Initial load: 8 ürün göster
  • Kullanıcı scroll ederse veya butona tıklarsa geri kalan 9 ürünü AJAX ile yükle
  • Beklenen kazanç: ~1 saniye (17 thumbnail → 8 thumbnail)

🟢 6. Düşük: Search Queries Cache Düşük Öncelik

Beklenen Kazanç: 114ms → ~5ms (cache hit durumunda)

Strateji: Popüler aramalar sonucunu 1 saat cache'le

Cache::remember('popular_searches', 3600, function() { return DB::table('search_queries') ->where('is_popular', true) ->where('is_hidden', false) ->groupBy('query') ->select('query', DB::raw('MAX(slug) as slug'), DB::raw('COUNT(*) as search_count')) ->orderBy('search_count', 'desc') ->limit(10) ->get(); });

📈 Beklenen Performans Kazancı

Optimizasyon Mevcut Süre Hedef Süre Kazanç
Database Index'leri 946ms ~50ms 18x
Blog Query Optimize 422ms ~20ms 21x
Thumbnail Cache 4.1s ~50ms 82x
Response Cache 2.3s ~100ms 23x
TOPLAM (Homepage) 8.3s ~500ms 16x
Not: Bu kazançlar kümülatiftir. Tüm optimizasyonlar uygulandığında homepage yüklenme süresi 8.3s → 500ms altına inebilir.

🎯 Aksiyon Planı (Adım Adım)

Adım 1: Database Index'leri Ekle (30 dakika)

  • Migration dosyası oluştur (4 index için)
  • Local/Staging'de test et
  • Production'da ALGORITHM=INPLACE, LOCK=NONE ile çalıştır
  • EXPLAIN query'leri ile doğrula

Adım 2: Blog Query'sini Bul ve Optimize Et (20 dakika)

  • Layout dosyalarında (header, footer, sidebar) blog query'sini bul
  • whereHas() yerine with() + filter() kullan
  • Cache ekle (5 dakika TTL)
  • Test et ve query süresini ölç

Adım 3: Thumbnail Cache Sistemi Kur (1 saat)

  • Thumbmaker cache mekanizmasını kontrol et
  • Eksikse: Upload sırasında preset boyutlarda thumbnail oluştur
  • HTTP Cache header'ları ekle (1 yıl max-age)
  • Mevcut ürünler için thumbnail'leri batch oluştur (artisan command)

Adım 4: Response Cache'i Kontrol Et (15 dakika)

  • Route middleware'lerini kontrol et
  • Redis connection'ı test et
  • Cache header'ları kontrol et (Postman/curl)
  • Gerekirse middleware sırasını düzenle

Adım 5: Test ve Doğrulama (30 dakika)

  • Tüm sayfaları test et (homepage, ürün detay, blog, shop)
  • Telescope'ta query sürelerini kontrol et
  • Google PageSpeed Insights ile skor al
  • Gerçek kullanıcı testi yap
Toplam Tahmini Süre: 2-3 saat. İlk 3 adım uygulanırsa bile performans 10x artacaktır.

⚠️ Dikkat Edilmesi Gerekenler

Production'da Index Ekleme

  • Index eklerken ALGORITHM=INPLACE, LOCK=NONE kullan (table lock olmaz)
  • Peak saatlerde yapma (gece 02:00 - 06:00 arası ideal)
  • İlk önce staging'de test et
  • Backup al!
Float to Int Precision Warning: Console'da görünen float → int precision hatası (satır 56) düzeltilmeli. Bu performansı etkilemez ama code quality için önemli. round() veya number_format() kullan.