Debate

PHP MySQL Performans Optimizasyonu

Iniciado por NocturneX · 09 jul 2026 14:41 · 17 Visitas · 0 Respuestas
Autor del tema #0
Bir web uygulamasının kalbi genellikle veritabanıdır, değil mi? PHP ile geliştirme yaparken MySQL'in gücünden faydalanıyoruz, ancak zamanla, özellikle trafik arttıkça veya veri hacmi büyüdükçe, performans sorunları kaçınılmaz hale gelebiliyor. "Sayfalar yavaş açılıyor," "sorgular çok uzun sürüyor," gibi şikayetler hepimizin başına gelmiştir. Peki, bu darboğazları nasıl aşarız, uygulamalarımızı nasıl daha hızlı ve ölçeklenebilir hale getiririz? Gelin, bu konuyu derinlemesine inceleyelim.

En temelden başlayalım: İndeksleme. Bir veritabanı tablosundaki indeksler, adeta bir kitabın içindekiler veya dizin sayfası gibidir. Ne kadar büyük olursa olsun, aradığınız bilgiye çok daha hızlı ulaşmanızı sağlar. Düşünsenize, 1 milyon satırlık bir tabloda belirli bir kullanıcı ID'sini arıyorsunuz... İndeks yoksa, MySQL tüm satırları tek tek taramak zorunda kalır, ki bu da tam bir felaket. Oysa doğru bir indeksle, saniyeler içinde sonuca ulaşırsınız. Peki, nerede kullanmalıyız bu indeksleri? Genellikle
CODE
1WHERE
,
CODE
1JOIN
,
CODE
1ORDER BY
ve
CODE
1GROUP BY
cümlelerinde sıkça kullandığımız sütunlarda indeks oluşturmak akıllıca bir hareket. Örneğin, bir
CODE
1users
tablosunda
CODE
1email
sütununda sıkça arama yapıyorsanız veya
CODE
1created_at
sütununa göre sıralama yapıyorsanız, bu sütunlara indeks eklemek uygulamanızın nefes almasını sağlar. Tabii her sütuna indeks eklemek de çözüm değil, çünkü indeksler de yer kaplar ve
CODE
1INSERT
,
CODE
1UPDATE
,
CODE
1DELETE
işlemlerini yavaşlatır. Bu yüzden altın kural: İhtiyaç duyulan yerlere, doğru indeksleri atmak.

CODE
123
CREATE INDEX idx_users_email ON users (email);
CREATE INDEX idx_products_category_price ON products (category_id, price);


Şu
CODE
1EXPLAIN
komutunu kullanmayı alışkanlık haline getirin. Bir sorgunun nasıl çalıştığını, hangi indeksleri kullandığını veya kullanmadığını, kaç satır taradığını size açıkça gösterir. Bu, sorgu optimizasyonunun olmazsa olmazıdır.

Gelelim Sorgu Optimizasyonuna. Bu konuda yapılabilecek o kadar çok şey var ki...
  • CODE
    1SELECT [i]
    kullanmaktan kaçının:
    Gerçekten ihtiyacınız olan sütunları belirtin. Neden mi? Çünkü
    CODE
    1[/i]
    kullanmak, istemediğiniz verileri de veritabanından çekmek demek. Bu hem ağ trafiğini artırır hem de MySQL'in daha fazla veri okumasına neden olur. Diyelim ki sadece kullanıcının adını ve soyadını istiyorsunuz, o zaman
    CODE
    1SELECT first_name, last_name FROM users
    yazın. Basit ama etkili.
  • CODE
    1JOIN
    vs. Alt Sorgular:
    Genellikle
    CODE
    1JOIN
    işlemleri alt sorgulara göre daha performanslıdır, çünkü MySQL
    CODE
    1JOIN
    için daha optimize edilmiş algoritmalar kullanır. Ancak her zaman değil. Bazen
    CODE
    1EXISTS
    ile kontrol etmek, büyük tablolarla
    CODE
    1JOIN
    yapmaktan daha iyi olabilir. Duruma göre değerlendirmek lazım.
  • CODE
    1WHERE
    cümlelerinde
    CODE
    1OR
    yerine
    CODE
    1UNION
    veya
    CODE
    1IN
    kullanmak:
    Özellikle karmaşık
    CODE
    1OR
    koşulları, indeks kullanımını engelleyebilir.
    CODE
    1UNION ALL
    veya
    CODE
    1IN
    ile sorguyu parçalamak, MySQL'in indeksleri daha verimli kullanmasını sağlayabilir.
  • CODE
    1LIMIT
    ve
    CODE
    1OFFSET
    ile sayfalama:
    Büyük veri setlerinde sayfalama yaparken
    CODE
    1OFFSET
    değeri çok büyüdüğünde performans düşer. Neden mi? Çünkü MySQL,
    CODE
    1OFFSET
    kadar satırı atlamak için yine de okumak zorunda kalır. Bu durumda, son görülen ID'yi kullanarak bir sonraki sayfayı getirmek (
    CODE
    1WHERE id > last_seen_id LIMIT N
    ) çok daha verimli bir yaklaşımdır.
  • Fonksiyonları
    CODE
    1WHERE
    cümlelerinde kullanmaktan kaçının:
    CODE
    1WHERE DATE(created_at) = '2023-01-01'
    gibi bir ifade,
    CODE
    1created_at
    sütunundaki indeksi kullanamaz. Çünkü MySQL her satır için
    CODE
    1DATE()
    fonksiyonunu çalıştırmak zorunda kalır. Bunun yerine,
    CODE
    1WHERE created_at >= '2023-01-01 00:00:00' AND created_at < '2023-01-02 00:00:00'
    gibi bir aralık belirtmek, indeksi aktif hale getirir.

Veritabanı Yapısı ve Normalizasyon da kritik bir konu.
  • Doğru veri tiplerini seçin: Bir sütun için
    CODE
    1INT
    yeterliyken
    CODE
    1BIGINT
    kullanmak,
    CODE
    1VARCHAR(255)
    yerine
    CODE
    1TEXT
    kullanmak gereksiz yere yer kaplar ve performansı olumsuz etkiler. Mümkün olan en küçük ve en uygun veri tipini kullanın.
  • Normalizasyon seviyesi: Veritabanı tasarımında normalizasyon, veri tekrarını azaltmak ve tutarlılığı artırmak için önemlidir. Ancak bazen, özellikle yoğun okuma yapılan sistemlerde, denormalizasyon yapmak performans artışı sağlayabilir. Örneğin, bir kullanıcının toplam sipariş sayısını her seferinde hesaplamak yerine, bu bilgiyi
    CODE
    1users
    tablosunda bir sütunda tutmak ve güncel tutmak, okuma performansını artırabilir. Tabii bu, yazma işlemlerini biraz daha karmaşık hale getirir. Bir denge bulmak şart.
  • CODE
    1ENUM
    vs. Lookup Tabloları:
    Sabit ve az sayıda seçenek içeren alanlar için
    CODE
    1ENUM
    kullanmak yer kazandırabilir. Ancak bu seçenekler zamanla değişebilecekse veya daha fazla detay içerecekse, ayrı bir lookup tablosu kullanmak daha esnektir ve veritabanı tutarlılığı açısından daha iyidir.

Şimdi PHP tarafına, yani Uygulama Seviyesi Optimizasyonlarına geçelim. MySQL ne kadar hızlı olursa olsun, PHP kodunuz kötü yazılmışsa yine de yavaşlık yaşarsınız.
  • Veritabanı Bağlantıları: Her istekte yeni bir veritabanı bağlantısı açıp kapatmak bir maliyettir. Persistent bağlantılar (
    CODE
    1PDO::ATTR_PERSISTENT => true
    ) bu maliyeti azaltabilir, ancak dikkatli kullanılmalı. Yanlış kullanıldığında kaynak sızıntılarına veya beklenmedik durumlara yol açabilirler. Genellikle, modern framework'ler ve container'lar bu durumu daha iyi yönetir.
  • Veri Çekme ve İşleme: Büyük sonuç kümeleriyle çalışırken tüm veriyi tek seferde belleğe yüklemek yerine, satır satır işlemek (
    CODE
    1fetch
    metotlarını kullanırken dikkatli olmak) bellek kullanımını azaltır. Özellikle milyonlarca satırı işleyen batch script'lerde bu hayati önem taşır.
  • N+1 Sorgu Problemi: ORM kullanıyorsanız, bu sorunla karşılaşma olasılığınız yüksek. Bir ana sorguyla N adet kayıt çekip, sonra her kayıt için ayrı ayrı detaylarını çekmek N+1 sorgu problemidir. Örneğin, 100 kullanıcı çekip, her kullanıcının en son siparişini ayrı bir sorguyla çekmek 101 sorgu demektir.
    CODE
    1JOIN
    veya eager loading tekniklerini kullanarak bu 101 sorguyu tek bir sorguya indirmek mümkündür.

Caching konusu, performans optimizasyonunun en güçlü silahlarından biri.
  • OPcode Önbellekleme (OPcache): PHP kodunuz her çalıştığında derlenir. OPcache, derlenmiş kodu bellekte tutarak bu derleme adımını atlar. Bu, saf PHP performansı için olmazsa olmazdır. Neredeyse tüm modern PHP kurulumlarında varsayılan olarak gelir ve düzgün yapılandırıldığından emin olunması gerekir.
  • Uygulama Seviyesi Önbellekleme (Redis, Memcached): Sıkça okunan ama nadiren değişen verileri (kullanıcı profilleri, ayarlar, ürün listeleri vb.) veritabanından çekmek yerine Redis veya Memcached gibi hızlı anahtar-değer depolarında önbelleğe almak, veritabanı üzerindeki yükü inanılmaz derecede azaltır. Bu, uygulamanızın ölçeklenebilirliğini doğrudan etkiler.
  • Veritabanı Önbelleği (MySQL Query Cache - Eskidi!): MySQL'in eski sürümlerinde bir sorgu önbelleği vardı. Ancak bu önbellek, bir tabloda küçücük bir değişiklik olduğunda bile tüm önbelleği geçersiz kıldığı için çoğu zaman performansı artırmaktan çok düşürüyordu. Bu yüzden MySQL 5.7.20'den itibaren kullanımdan kaldırıldı ve MySQL 8.0'dan itibaren tamamen kaldırıldı. Artık bu işi uygulama seviyesinde Redis/Memcached ile veya daha düşük seviyede InnoDB Buffer Pool ile yapıyoruz.

Sunucu Seviyesi Optimizasyonları da göz ardı edilmemeli.
  • MySQL Yapılandırması (
    CODE
    1my.cnf
    ):

  • CODE
    1innodb_buffer_pool_size
    :
    InnoDB tablolarının ve indekslerinin bellekte tutulduğu alandır. Genellikle sunucudaki RAM'in %50-%80'i kadar ayarlanması önerilir. Bu, disk I/O'yu büyük ölçüde azaltır.
  • CODE
    1max_connections
    :
    Aynı anda kaç bağlantıya izin verileceğini belirler. Uygulamanızın ihtiyaçlarına göre ayarlanmalı. Çok düşük olması bağlantı reddine, çok yüksek olması kaynak tüketimine yol açabilir.
  • CODE
    1slow_query_log
    :
    Belirli bir süreden daha uzun süren sorguları loglamanızı sağlar. Performans darboğazlarını tespit etmek için paha biçilmez bir araçtır. Mutlaka aktif edin ve düzenli olarak kontrol edin.
  • PHP Yapılandırması (
    CODE
    1php.ini
    ):

  • CODE
    1memory_limit
    :
    Bir PHP script'inin kullanabileceği maksimum bellek miktarını belirler. Büyük veri setleriyle çalışırken veya karmaşık işlemler yaparken bu limiti artırmak gerekebilir.
  • CODE
    1max_execution_time
    :
    Bir script'in çalışmasına izin verilen maksimum süredir. Uzun süren işlemler için artırılması gerekebilir, ancak sonsuz döngüleri veya hatalı kodları maskelememesi için dikkatli olunmalı.
  • Donanım ve Altyapı:
  • SSD kullanımı: Veritabanı sunucularında SSD diskler, geleneksel HDD'lere göre kat kat daha hızlı I/O performansı sunar. Bu, özellikle disk tabanlı işlemleri yoğun olan veritabanları için devasa bir fark yaratır.
  • Yeterli RAM: MySQL'in verileri ve indeksleri bellekte tutabilmesi için yeterli RAM'e sahip olmak, disk okuma ihtiyacını azaltarak performansı artırır.

Son olarak, İzleme ve Analiz olmadan performans optimizasyonu körlemesine ilerlemek gibidir.
  • CODE
    1EXPLAIN
    komutu:
    Tekrar ediyorum, her sorgunuzu analiz etmek için kullanın.
  • Slow Query Log: Periyodik olarak kontrol ederek optimize edilmesi gereken sorguları tespit edin.
  • Percona Toolkit: Özellikle
    CODE
    1pt-query-digest
    gibi araçları kullanarak slow query loglarını daha anlamlı raporlara dönüştürebilirsiniz.
  • APM (Application Performance Monitoring) Araçları: New Relic, Datadog, Blackfire gibi araçlar, uygulamanızın ve veritabanınızın performansını gerçek zamanlı olarak izlemenizi, darboğazları kolayca tespit etmenizi sağlar.
  • Xdebug: Geliştirme ortamında PHP kodunuzun performansını profilleyerek, hangi satırların veya fonksiyonların daha fazla zaman aldığını görebilirsiniz.

Performans optimizasyonu tek seferlik bir iş değildir, sürekli bir süreçtir. Uygulamanız büyüdükçe, kullanıcı sayısı arttıkça veya yeni özellikler eklendikçe, yeni darboğazlar ortaya çıkacaktır. Bu yüzden düzenli olarak izlemek, test etmek ve optimize etmek gerekiyor.

Peki, sizin bu konudaki tecrübeleriniz neler? Hangi optimizasyon teknikleri sizin için en çok işe yaradı? Ya da karşılaştığınız en ilginç performans sorunu neydi ve nasıl çözdünüz? Deneyimlerinizi ve önerilerinizi merak ediyorum...

Debes haber iniciado sesión para responder.

0 citas seleccionadas