Merhaba arkadaşlar, bugün sizlere MySQL 8.0 sunucularımızda performansı kökten etkileyen iki önemli konuyu, indeksleme stratejilerini ve yavaş sorgu log analizini, kendi tecrübelerim ışığında anlatacağım. Doğru indeksleme, veritabanınızın motor gücünü artırırken, yavaş sorgu logları da bu motorun nerede zorlandığını gösteren en değerli tanı araçlarıdır. Bu rehberi uygulayarak sorgu sürelerinizi ciddi oranda düşürebilirsiniz.
Neden İndeks (Index) Kullanmalıyız?
Basitçe anlatmak gerekirse, indeksler, bir kitabın sonundaki "dizin" gibi çalışır. Tüm kitabı baştan sona okumak yerine, aradığınız kelimenin hangi sayfalarda olduğuna hızlıca bakarsınız. İndeksler de veritabanına, "şu koşula uyan kayıtlar şu fiziksel konumdadır" diyerek tüm tabloyu taramak (Full Table Scan) yerine doğrudan ilgili kayıtlara gitmesini sağlar. Bu, özellikle milyonlarca kayıtlı tablolarda saniyelerden milisaniyelere inen bir performans farkı yaratır.
Temel ve Bileşik İndeks Stratejileri
İndeks oluştururken en sık yapılan hata, her sütuna ayrı ayrı indeks açmaktır. Bu, yazma performansını düşürür ve optimizatörün kafasını karıştırabilir. İşte benim genelde uyguladığım stratejiler:
1. WHERE, JOIN ve ORDER BY cümlelerinizdeki sütunlara öncelik verin.
2. Bileşik (Composite) İndeksler kullanın: Sık birlikte kullanılan sütunları tek bir indekste toplayın. Örneğin, `status` ve `created_date` sütunlarına sık sık birlikte sorgu atıyorsanız, ikisini içeren bir bileşik indeks daha verimli olacaktır.
Bu indeks, `WHERE status='shipped' ORDER BY created_date DESC` gibi bir sorguyu inanılmaz hızlandırır.
3. Kardinalitesi yüksek sütunları seçin: Kardinalite, bir sütundaki benzersiz değerlerin sayısıdır. `cinsiyet` (M/F) gibi düşük kardinaliteli bir sütun yerine, `email` veya `kullanici_id` gibi yüksek kardinaliteli sütunlara indeks daha çok fayda sağlar.
Yavaş Sorgu Log'unu (Slow Query Log) Aktif Etmek
Hangi sorguların optimize edilmesi gerektiğini bilmek için önce onları tespit etmeliyiz. MySQL'in yavaş sorgu log'u tam da bunun için var. Loglamayı geçici olarak çalışma anında da açabilirsiniz, kalıcı olarak config dosyasından da. Ben kalıcı yapılandırmayı öneriyorum.
Öncelikle, MySQL config dosyamızı (genelde /etc/mysql/mysql.conf.d/mysqld.cnf veya /etc/my.cnf) açıyoruz.
`long_query_time = 2`: 2 saniyeden uzun süren tüm sorguları loglar. Bu değeri ihtiyacınıza göre 1 veya 0.5 yapabilirsiniz.
`log_queries_not_using_indexes = 1`: İndeks kullanmayan sorguları da loglar (ÇOK FAYDALI ama log dosyasını şişirebilir, dikkatli olun).
Ayarları kaydettikten sonra MySQL'i yeniden başlatalım.
Log Dosyası Konumuna Dikkat!
`slow_query_log_file` ile belirttiğimiz dosyanın, MySQL prosesinin (`mysql` kullanıcısının) yazma izni (write permission) olduğundan emin olun. Aksi halde log tutulamaz.
Yavaş Sorgu Loglarını Analiz Etmek: mysqldumpslow
Loglar bir süre sonra büyüyecektir. Ham log dosyasını okumak zor olabilir. Neyse ki MySQL, `mysqldumpslow` adında harika bir parse aracı ile gelir.
En yavaş 10 sorguyu görmek için:
Sorguları, toplam süreye göre sıralamak için:
İndeks kullanmayan sorguları sayısına göre gruplamak için:
Bu araç, benzer sorguları gruplayıp, her birinden kaç kez çalıştığını, ortalama/toplam süresini gösterir. Böylece optimizasyon için önceliği, en çok zaman kaybettiren ve en sık çalışan sorgulara verebilirsiniz.
Optimizasyon Sonrası: EXPLAIN Sihirbazı
Yavaş sorgu log'undan bir sorgu yakaladınız. Hemen indeks eklemeye atlamayın. Önce `EXPLAIN` komutu ile sorgunun nasıl çalıştığını (execution plan) inceleyin.
`EXPLAIN` çıktısında özellikle şu sütunlara bakın:
`type`: `ALL` görüyorsanız, bu tam tablo taraması demektir (Kötü). `index`, `range`, `ref` gibi değerler daha iyidir.
`key`: MySQL'in kullandığı indeks. `NULL` ise indeks kullanılmıyor demektir.
`rows`: Tahmini tarayacağı satır sayısı. Bu değer ne kadar düşükse o kadar iyi.
`EXPLAIN` analizi, nereye indeks ekleyeceğiniz konusunda size net ve bilimsel bir yol gösterir.
Sonuç olarak, performans optimizasyonu bir kerede yapılıp biten bir iş değil, sürekli izleme ve iyileştirme döngüsüdür. Yavaş sorgu log'unu düzenli olarak (örneğin haftada bir) analiz etmeyi alışkanlık haline getirin.
Ben genelde bu akışı takip ediyorum: Log'u aç -> Bir hafta bekle -> `mysqldumpslow` ile analiz et -> `EXPLAIN` ile sorunlu sorguları incele -> Hedefe yönelik indeks oluştur -> Performansı ölç. Peki siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Farklı kullandığınız araçlar veya yöntemler var mı? Sorusu olan aşağıya yazsın, beraber tartışalım.
Basitçe anlatmak gerekirse, indeksler, bir kitabın sonundaki "dizin" gibi çalışır. Tüm kitabı baştan sona okumak yerine, aradığınız kelimenin hangi sayfalarda olduğuna hızlıca bakarsınız. İndeksler de veritabanına, "şu koşula uyan kayıtlar şu fiziksel konumdadır" diyerek tüm tabloyu taramak (Full Table Scan) yerine doğrudan ilgili kayıtlara gitmesini sağlar. Bu, özellikle milyonlarca kayıtlı tablolarda saniyelerden milisaniyelere inen bir performans farkı yaratır.
İndeks oluştururken en sık yapılan hata, her sütuna ayrı ayrı indeks açmaktır. Bu, yazma performansını düşürür ve optimizatörün kafasını karıştırabilir. İşte benim genelde uyguladığım stratejiler:
1. WHERE, JOIN ve ORDER BY cümlelerinizdeki sütunlara öncelik verin.
2. Bileşik (Composite) İndeksler kullanın: Sık birlikte kullanılan sütunları tek bir indekste toplayın. Örneğin, `status` ve `created_date` sütunlarına sık sık birlikte sorgu atıyorsanız, ikisini içeren bir bileşik indeks daha verimli olacaktır.
SQL:
CREATE INDEX idx_status_created ON orders (status, created_date);
Bu indeks, `WHERE status='shipped' ORDER BY created_date DESC` gibi bir sorguyu inanılmaz hızlandırır.
3. Kardinalitesi yüksek sütunları seçin: Kardinalite, bir sütundaki benzersiz değerlerin sayısıdır. `cinsiyet` (M/F) gibi düşük kardinaliteli bir sütun yerine, `email` veya `kullanici_id` gibi yüksek kardinaliteli sütunlara indeks daha çok fayda sağlar.
Hangi sorguların optimize edilmesi gerektiğini bilmek için önce onları tespit etmeliyiz. MySQL'in yavaş sorgu log'u tam da bunun için var. Loglamayı geçici olarak çalışma anında da açabilirsiniz, kalıcı olarak config dosyasından da. Ben kalıcı yapılandırmayı öneriyorum.
Öncelikle, MySQL config dosyamızı (genelde /etc/mysql/mysql.conf.d/mysqld.cnf veya /etc/my.cnf) açıyoruz.
INI:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
`long_query_time = 2`: 2 saniyeden uzun süren tüm sorguları loglar. Bu değeri ihtiyacınıza göre 1 veya 0.5 yapabilirsiniz.
`log_queries_not_using_indexes = 1`: İndeks kullanmayan sorguları da loglar (ÇOK FAYDALI ama log dosyasını şişirebilir, dikkatli olun).
Ayarları kaydettikten sonra MySQL'i yeniden başlatalım.
Bash:
sudo systemctl restart mysql
`slow_query_log_file` ile belirttiğimiz dosyanın, MySQL prosesinin (`mysql` kullanıcısının) yazma izni (write permission) olduğundan emin olun. Aksi halde log tutulamaz.
Loglar bir süre sonra büyüyecektir. Ham log dosyasını okumak zor olabilir. Neyse ki MySQL, `mysqldumpslow` adında harika bir parse aracı ile gelir.
En yavaş 10 sorguyu görmek için:
Bash:
sudo mysqldumpslow -t 10 /var/log/mysql/mysql-slow.log
Sorguları, toplam süreye göre sıralamak için:
Bash:
sudo mysqldumpslow -s at /var/log/mysql/mysql-slow.log
İndeks kullanmayan sorguları sayısına göre gruplamak için:
Bash:
sudo mysqldumpslow -g "index" /var/log/mysql/mysql-slow.log
Bu araç, benzer sorguları gruplayıp, her birinden kaç kez çalıştığını, ortalama/toplam süresini gösterir. Böylece optimizasyon için önceliği, en çok zaman kaybettiren ve en sık çalışan sorgulara verebilirsiniz.
Yavaş sorgu log'undan bir sorgu yakaladınız. Hemen indeks eklemeye atlamayın. Önce `EXPLAIN` komutu ile sorgunun nasıl çalıştığını (execution plan) inceleyin.
SQL:
EXPLAIN SELECT FROM users WHERE email = 'admin@bingunluk.com';
`EXPLAIN` çıktısında özellikle şu sütunlara bakın:
`type`: `ALL` görüyorsanız, bu tam tablo taraması demektir (Kötü). `index`, `range`, `ref` gibi değerler daha iyidir.
`key`: MySQL'in kullandığı indeks. `NULL` ise indeks kullanılmıyor demektir.
`rows`: Tahmini tarayacağı satır sayısı. Bu değer ne kadar düşükse o kadar iyi.
`EXPLAIN` analizi, nereye indeks ekleyeceğiniz konusunda size net ve bilimsel bir yol gösterir.
Sonuç olarak, performans optimizasyonu bir kerede yapılıp biten bir iş değil, sürekli izleme ve iyileştirme döngüsüdür. Yavaş sorgu log'unu düzenli olarak (örneğin haftada bir) analiz etmeyi alışkanlık haline getirin.
Ben genelde bu akışı takip ediyorum: Log'u aç -> Bir hafta bekle -> `mysqldumpslow` ile analiz et -> `EXPLAIN` ile sorunlu sorguları incele -> Hedefe yönelik indeks oluştur -> Performansı ölç. Peki siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Farklı kullandığınız araçlar veya yöntemler var mı? Sorusu olan aşağıya yazsın, beraber tartışalım.