Yazılarımız

Veri Akademi

SQL QUERY TUNİNG NEDİR? EXPLAİN PLAN OKUMA VE PERFORMANS İYİLEŞTİRME

Bir sorgu “doğru” sonucu üretip yine de yavaş olabilir. Üstelik sorun çoğu zaman tek bir satırda değil; yanlış indeks seçimi, hatalı join sırası, şişmiş istatistikler veya gereksiz veri okuması gibi zincirleme etkilerde saklıdır. SQL query tuning tam olarak bu noktada devreye girer: sorgunun ne yaptığını değil, nasıl yaptığını anlamayı ve iyileştirmeyi hedefler.

Bu yazıda, “SQL Query Tuning nedir?” sorusunu pratik bir çerçeveyle ele alacağız. Explain plan okuma mantığını, plan üzerindeki tipik risk işaretlerini ve adım adım performans iyileştirme tekniklerini öğreneceksiniz. Hedef; sadece tek seferlik hızlandırma değil, tekrar edilebilir bir analiz alışkanlığı kazanmaktır.

İster OLTP tarafında milisaniyeler kovalayın, ister raporlama sorgularında dakikaları dakikadan saniyeye indirin; yaklaşım aynıdır: ölç, planı yorumla, hipotez kur, değiştir, tekrar ölç. Yazının sonunda, SQL Performance & Query Tuning Eğitimi bağlantısıyla daha derin ve uygulamalı bir öğrenme yoluna da geçebilirsiniz.

Veritabanı performans panosunda gecikme grafikleri ve plan düğümleri birlikte izleniyor, odaklı analiz yaklaşımı vurgulanıyor

SQL Query Tuning: Tanım, Amaç ve Kapsam

SQL query tuning, bir sorgunun çalışması için harcanan süreyi ve kaynak tüketimini azaltmak amacıyla sorgunun yapısını, veri erişim yolunu ve veritabanı motorunun seçimlerini optimize etme sürecidir. Buradaki kritik nokta, “daha hızlı” hedefine rastgele hamlelerle değil, plan ve ölçüm verileriyle ilerlemektir.

Tuning kapsamı yalnızca sorgu metniyle sınırlı değildir. İndeks tasarımı, tablo istatistikleri, şema modelleme kararları, veri dağılımı, parametre kullanımı, cache davranışı, hatta izolasyon seviyesi bile sonuçları etkileyebilir. Bu yüzden tuning, tek bir teknik değil; bir mühendislik disiplini olarak ele alınmalıdır.

Tuning mi, refactoring mi: Sınır nerede?

Tuning çoğu zaman “mevcut işlevi koruyarak daha hızlı çalıştırma” demektir. Ancak bazı durumlarda sorguyu yeniden yazmak, materialized view kullanmak, özet tablo üretmek veya farklı bir okuma modeli tasarlamak gerekebilir. Bu noktada tuning ile refactoring iç içe geçer; karar için ölçümler, SLA ve bakım maliyeti birlikte değerlendirilir.

Performansın Temeli: Ölçmeden Tuning Yapılmaz

Yanlış metrikle yapılan tuning, doğru sonucu vermeyebilir. Örneğin sorgu süresi düşerken CPU artabilir, ya da tek oturum hızlanırken eşzamanlı yükte kilit beklemeleri çoğalabilir. Bu yüzden hedef metrikleri netleştirmek gerekir: toplam süre, CPU, logical/physical read, temp kullanımı, network round-trip, kilit beklemeleri gibi.

İzlenecek metrikler ve hızlı kontrol listesi

  • Toplam süre ve 95/99 persentil gecikme
  • Logical read / physical read oranı (I/O baskısı)
  • Rows returned vs rows scanned farkı (seçicilik)
  • Join cardinality sapmaları (yanlış tahmin)
  • Temp alanı ve sort/hash spill işaretleri
  • Wait event türleri (I/O, lock, latch vb.)

İlk teşhis için “en pahalı” sorgu tek başına yeterli olmayabilir. Kimi zaman sorun, orta maliyetli ama çok sık çalışan sorgulardır. Bu nedenle periyot bazlı izleme (query store, AWR/ASH, slow query log, pg_stat_statements gibi) ile konuşmak daha sağlıklı olur.

Yürütme planında yüksek maliyetli düğüm kırmızıyla işaretlenmiş, satır tahmini ile gerçek satır farkı belirgin görünüyor

Explain Plan Okuma: Yürütme Planı Ne Söyler?

Explain plan okuma, veritabanı motorunun sorguyu çalıştırmak için seçtiği adımları görselleştirmektir. Plan; hangi indeksin kullanıldığını, join stratejisini (nested loop, hash join, merge join), filtreleme sırasını, sıralama ve agregasyonların nerede yapıldığını gösterir. Tuning’de amaç, planın “mantıklı” olup olmadığını doğrulamaktır.

Plan yorumlarken iki temel kavramı ayırın: tahmin (optimizer’ın öngörüsü) ve gerçek (runtime ölçümü). Pek çok sistemde “EXPLAIN ANALYZE” veya benzeri çıktı ile gerçek satır sayıları ve süreler görülebilir. Tahmin ile gerçek arasındaki uçurum, yanlış indeks veya güncel olmayan istatistik gibi problemleri işaret eder.

Plan düğümleri: Yaygın risk işaretleri

Aşağıdaki işaretler çoğu ortamda alarm niteliğindedir:

  1. Tam tablo taraması (selectivity düşük değilse gereksiz I/O)
  2. Gereksiz “Sort” veya büyük “Hash” (temp spill riski)
  3. Join sırası nedeniyle büyük ara sonuçlar
  4. Predicate’in indekste kullanılmaması (non-sargable koşullar)
  5. Rows estimate ile actual rows arasında büyük fark

Örnek: Planı analiz ederek darboğazı yakalamak

Aşağıdaki örnek PostgreSQL’de tipik bir inceleme akışını gösterir. Amaç, hangi düğümün maliyeti büyüttüğünü ve satır sayılarının nerede şiştiğini görmek:

EXPLAIN (ANALYZE, BUFFERS)
SELECT o.id, o.order_date, c.segment, SUM(oi.qty * oi.unit_price) AS total_amount
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
JOIN customers c ON c.id = o.customer_id
WHERE o.order_date >= DATE '2026-01-01'
  AND c.segment = 'enterprise'
GROUP BY o.id, o.order_date, c.segment
ORDER BY total_amount DESC
LIMIT 50;

Bu tür bir sorguda sık görülen problem, önce büyük bir join sonucu üretip sonra filtrelemek ya da sıralamayı çok geniş bir veri üzerinde yapmak olabilir. Plan çıktısında “Sort” düğümünün üstünde milyonlarca satır görüyorsanız, LIMIT’e rağmen sıralama maliyeti patlayabilir. Çözüm, daha erken filtreleme, uygun indeks veya farklı bir sıralama yaklaşımı olabilir.

En Büyük Kazanç Alanı: İndeks ve Erişim Yolları

İndeksler, tuning’in en güçlü araçlarından biridir; fakat rastgele indeks eklemek uzun vadede yazma maliyetini artırır ve planı karmaşıklaştırır. Doğru yaklaşım, sorgunun filtre ve join koşullarına bakarak, seçiciliği yüksek alanları ve erişim düzenini hedeflemektir.

Sargable koşullar ve indeksin kullanılmaması

İndeksin kullanılmamasının yaygın sebeplerinden biri, koşulun “sargable” olmamasıdır. Örneğin, kolon üzerinde fonksiyon uygulamak, engine’in indeks aralığını kullanmasını engelleyebilir. Tarih kolonunu stringe çevirip karşılaştırmak, lower/upper ile filtrelemek gibi örnekler sık görülür. Mümkünse dönüşümü parametreye taşıyın veya fonksiyon bazlı indeks gibi seçenekleri değerlendirin.

Aşağıdaki örnekte, fonksiyon kullanan filtre yerine aralık filtresi tercih edilir:

-- Kaçınılması gereken (indeks kullanımını zorlaştırabilir)
SELECT *
FROM orders
WHERE TO_CHAR(order_date, 'YYYY-MM') = '2026-01';

-- Tercih edilen (aralık filtresi ile indeks dostu)
SELECT *
FROM orders
WHERE order_date >= DATE '2026-01-01'
  AND order_date <  DATE '2026-02-01';

Join Optimizasyonu: Doğru Stratejiyi Seçtirmek

Join performansı, özellikle çok tablo içeren sorgularda belirleyicidir. Veritabanı motoru; nested loop, hash join veya merge join gibi yöntemlerden birini seçer. Doğru seçimi etkileyen başlıklar: doğru indeksler, doğru istatistikler, filtreleme sırası ve beklenen satır sayılarıdır.

Join sırası ve ara sonuçları küçültme

Genel kural: önce seçiciliği yüksek filtreleri uygulayarak ara sonuçları küçültmek, sonra join etmek daha verimlidir. Ancak bu her zaman sorgu metnindeki sırayla olmaz; optimizer kendi planını kurar. Yine de sorguyu daha “yönlendirilebilir” hale getirmek için gereksiz kolonları erken taşımamak, uygun where koşulları yazmak ve join anahtarlarını temiz tutmak önemlidir.

Join stratejilerini karşılaştıran bir performans ekranında nested loop ve hash join süreleri yan yana görülüyor, karar noktası vurgulanıyor

İstatistikler, Cardinality Tahmini ve Plan Sapmaları

Optimizer’ın en kritik girdisi istatistiklerdir. Eğer tablo büyümüş, veri dağılımı değişmiş veya kolon korelasyonları farklılaşmışsa, optimizer yanlış cardinality tahmini yapabilir. Sonuç: yanlış join stratejisi, yanlış indeks seçimi ve beklenmeyen I/O artışı.

Plan sapmasını anlamanın pratik yolu

Çoğu platformda plan çıktısında “estimated rows” ve “actual rows” benzeri alanlar bulunur. Fark çok büyükse, tuning adımlarını şunlara göre sıralayın:

  • İstatistiklerin güncelliğini kontrol etme
  • Dağılımı bozan uç değerleri belirleme
  • Filtre kolonları için histogram/extended stats seçeneklerini değerlendirme
  • Parametre duyarlılığı (bind peeking) ihtimalini inceleme

Burada amaç “planı zorla” değil, optimizer’ın doğru karar vermesini sağlayacak veriyi ve yapıyı sunmaktır. Güncel istatistik çoğu zaman en ucuz ve etkili kazanımı getirir.

Sorgu Yeniden Yazımı: Daha Az Veri, Daha Az İş

Bazen tek bir indeks eklemek yetmez; sorgu metninin daha verimli bir şekle evrilmesi gerekir. Yeniden yazımda hedef, gereksiz satırları erken elemek, pahalı işlemleri azaltmak ve engine’in optimize edebileceği bir form sunmaktır.

Gereksiz SELECT * ve kolon şişmesi

Raporlama dışı senaryolarda “SELECT *” kullanımı, gereksiz I/O ve ağ yükü oluşturabilir. Ayrıca geniş satır taşıma, join ve sort maliyetlerini artırır. İhtiyaç duyulan kolonları seçmek, özellikle yüksek trafikli servislerde fark yaratır. Bu, basit ama etkili bir tuning adımıdır.

Pagination ve sıralama maliyetini düşürme

ORDER BY + OFFSET kombinasyonu, büyük offset değerlerinde maliyeti hızla büyütebilir. Bunun yerine “seek method” (son görülen anahtar üzerinden devam) yaklaşımı daha verimlidir. Ayrıca sıralanan kolonlar üzerinde uygun indeks, LIMIT ile birlikte ciddi kazanç sağlar.

İyileştirme Süreci: Adım Adım Tuning Akışı

Başarılı tuning, tekrarlanabilir bir süreç gerektirir. Aşağıdaki akış, günlük işlerde pratik bir yol haritası sunar:

  1. Hedef metriği belirle (süre, CPU, I/O, concurrency)
  2. Mevcut durumu ölç ve sorguyu izleme araçlarında yakala
  3. Explain plan ile yürütme adımlarını ve maliyeti gör
  4. Darboğaz düğümünü seç: scan, join, sort, aggregate
  5. Hipotez kur: indeks, yeniden yazım, istatistik, parametre
  6. Değişikliği uygula, tekrar ölç ve regresyon kontrolü yap

En kritik alışkanlık, tek seferde çok değişiklik yapmamak ve her değişikliğin etkisini ayrı ölçmektir. Böylece hangi adımın gerçekten değer ürettiği netleşir. Performans iyileştirme yalnızca hız değil, öngörülebilirlik ve sürdürülebilirlik demektir.

Sorgu iyileştirme akışını gösteren bir çalışma masasında ölçüm notları, plan çıktısı ve indeks taslağı birlikte yer alıyor, sistematik süreç anlatılıyor

Pratik İpuçları ve Sık Yapılan Hatalar

Son olarak, sahada en sık karşılaşılan hataları ve pratik ipuçlarını tek yerde toplayalım. Bu listeyi bir “tuning kontrol noktası” gibi kullanabilirsiniz:

  • İndeks eklemeden önce sorgu desenini ve yazma maliyetini değerlendirin
  • Join anahtarlarında veri tipi uyumsuzluğunu temizleyin
  • Filtre kolonlarında fonksiyon kullanımını azaltın
  • İstatistikleri düzenli güncelleyin; sapma varsa kök nedeni arayın
  • Planı sadece “cost” ile değil, gerçek süre ve buffer/I/O ile yorumlayın
  • Test ortamında hızlanan sorguyu, üretimde eşzamanlı yükte de doğrulayın

Öğrenmeyi hızlandırmak için gerçek senaryolar üzerinden ilerlemek önemlidir. Plan okumayı, indeks stratejilerini, join davranışlarını ve ölçüm pratiklerini daha sistemli ele almak isterseniz SQL Performance & Query Tuning Eğitimi içeriği size kapsamlı bir rota sunar.

Özetle: SQL query tuning, “sorgu yavaş” yakınmasını ölçülebilir ve yönetilebilir bir probleme dönüştürür. Explain plan okuma becerisiyle nerede zaman kaybettiğinizi görür, doğru iyileştirme hamleleriyle performansı kalıcı biçimde yukarı çekersiniz.

 VERİ AKADEMİ