Geliştiriciler bana sık sık aynı soruyu sorarlar: "API'm yavaş. Nereden başlamalıyım?" Genellikle verilen refleks, sunucuyu yükseltmek veya RAM'i iki katına çıkarmaktır. Bu para maliyetine yol açar ve nadiren kök sorunu çözer. Çoğu Laravel uygulamasında darboğaz veritabanı katmanında bulunur. Çerçevenin zarif sözdizimi, her Eloquent çağrısının sonunda SQL'e dönüştüğünü ve SQL'in genellikle sancıların başladığı yer olduğunu unutmayı kolaylaştırır.

Bir sunucu ayarına dokunmadan önce, sorgularınızı metodik bir şekilde inceleyin.

Doğru Teşhisle Başlayın

Karanlıkta optimizasyon yapmayın. Sorguları rastgele yeniden yazmak tahminden ibarettir ve tahmin yürütmek saatlerin boşa gitmesine neden olur.

En fazla toplam süreyi tüketen ifadeleri bulmanız gerekir. Uygulamanızı gerçek yük altında izleyin. Laravel Telescope, bir istek sırasında yürütülen her sorgunun zamanlamasıyla birlikte temiz bir görünümünü sunar. Laravel Debugbar ise yerel geliştirme sırasında bunları tarayıcınızda görünür kılarak anomalileri anında fark etmenizi sağlar. Canlı ortamdaki (production) sorunları yakalamanız gerektiğinde, MySQL Slow Query Log özelliğini etkinleştirin. Belirlediğiniz bir eşiği aşan ifadeleri kaydeder; bu da onu küçük veri setlerinde ortaya çıkmayan sürprizleri bulmak için ideal kılar. Daha büyük bir yapı çalıştırıyorsanız, bir Application Performance Monitoring aracı, yavaş HTTP uç noktalarını (endpoints) belirli veritabanı çağrılarıyla ilişkilendirebilir.

Verileri incelerken iki şeye bakın: mutlak yürütme süresi ve çağrı sıklığı. Kırk milisaniye süren bir sorgu, dakikada iki bin kez çalıştığını fark edene kadar zararsız görünebilir. Saatte bir kez çalışan üç saniyelik bir rapor, her sayfada çalışan yarım saniyelik bir aramadan daha az önemli olabilir. Önce yüksek etkili sorunları çözün.

Her Şeyi İstemeyi Bırakın

SELECT * kullanmak kolaydır. Aynı zamanda maliyetlidir. Model::all() yazdığınızda veya sütun isimlerini belirtmeden bir sonuç kümesi çektiğinizde, MySQL eşleşen her satır için tüm alanları çeker. Buna büyük metin alanları, JSON blob'ları ve tabloda bulunan diğer her şey dahildir. Sonuç kümesi büyür, bellek kullanımı artar ve yanıtı serileştirmek (serializing) için harcanan süre uzar.

Açık olun. Eğer denetleyicinizin (controller) sadece id, name ve email alanlarına ihtiyacı varsa, tam olarak bunları isteyin:

User::select('id', 'name', 'email')->get();

Query builder'da da aynı ilke geçerlidir. Daha küçük veri paketleri (payloads) ağ üzerinde daha hızlı hareket eder ve uygulama sunucunuzda daha az RAM tüketir. Bu, elde edilebilecek en ucuz kazanımlardan biridir; ancak Laravel SELECT * kullanımını varsayılan davranış haline getirdiği için bunu atlamak kolaydır.

Değişikliklerinize EXPLAIN Rehberlik Etsin

EXPLAIN komutunu çalıştırmadan asla yavaş bir sorguyu yeniden yapılandırmayın (refactor). MySQL'de EXPLAIN anahtar kelimesi, sorgu yürütme planını gösterir. Optimize edicinin (optimizer) verilerinizi tam olarak nasıl bulmayı planladığını ortaya çıkarır.

type sütununa dikkat edin. Eğer ALL görüyorsanız, MySQL tam tablo taraması (full table scan) yapıyor demektir. Bu, WHERE koşulunuzu karşılamak için her satırı okuduğu anlamına gelir. Optimize edicinin bir indeks kullanıp kullanmadığını görmek için key sütununa bakın. Ardından Extra sütununu kontrol edin. Eğer Using temporary veya Using filesort görürseniz, mevcut yapınız sorguyu düzgün bir şekilde karşılayamadığı için MySQL ara tablolar oluşturuyor veya bellekte sıralama yapıyor demektir.

MySQL istemcinizde EXPLAIN çalıştırın veya çıktıyı sizin için formatlayan bir araç kullanın. Planı gördüğünüzde, sorunun eksik bir indeks mi, kötü bir join mi yoksa motorun optimize edemediği bir koşul (predicate) mu olduğunu anlarsınız. Tahmin yürütmeye gerek kalmaz.

Bilinçli Şekilde İndeksleyin

İndeksler, aramaları hızlandırmak için en güçlü araçtır ancak yalnızca sorgulama şeklinizle eşleştiklerinde işe yararlar. Doğru indeks olmadan MySQL satır satır tarama yapar. Bu, bin satırlık bir tabloda geliştirme aşamasında sorunsuz görünebilir, ancak on milyon satırlık bir tabloda canlı ortamda çökebilir.

WHERE koşullarında sıkça görünen alanlar için tek sütunlu indekslerle başlayın. Sürekli status değerine göre filtreleme yapıyorsanız, status üzerine bir indeks ekleyin.

Bir sorgu birden fazla sütunu birlikte filtrelediğinde, bileşik (composite) indekslere geçin. İndeks içindeki sütunların sırası önemlidir çünkü MySQL bileşik indeksleri soldan sağa doğru okur. Buna "en soldaki önek kuralı" (leftmost prefix rule) denir. Sorgunuz önce user_id ile arama yapıp sonra created_at değerine göre sıralıyorsa, (user_id, created_at) üzerindeki bir bileşik indeks önemli ölçüde yardımcı olur. Sıralamayı tersine çevirirseniz, optimize edici filtreleme için indeksi hiç kullanmayabilir.

Her sütunu indekslemeyin. Her indeks; ekleme (insert), güncelleme (update) ve silme (delete) işlemlerine ek yük (overhead) getirir çünkü MySQL yapıyı korumak zorundadır. Onları, ölçüm sırasında bulduğunuz kalıplara dayanarak bilinçli bir şekilde ekleyin.

Fonksiyonları Sütunlardan Uzak Tutun

This mistake quietly disables indexes. When you wrap a column in a function inside a WHERE clause, MySQL cannot