Bilgi Bankası
PostgreSQLPerformans ve kapasite 15 dk 14.06.2026

PostgreSQL query planner neden yanlış plan seçer?

PostgreSQL bazen “indeks varken neden kullanmadı?” sorusunu sordurur. Çoğu zaman cevap planner’ın kötü olması değil, elindeki istatistiklerin, veri dağılımının veya sorgu biçiminin gerçeği eksik anlatmasıdır.

Bu yazı sana şu durumda yardımcı olur
  • indeks var ama sequential scan yapılıyor
  • bazı tenantlarda sorgu hızlı bazılarında çok yavaş
  • EXPLAIN tahmini satır ile gerçek satır çok farklı
  • ANALYZE uzun süredir çalışmamış
  • parametreli sorgular beklenmedik plan seçiyor
Yazıyı bitirince

PostgreSQL planner kararını daha doğru okuyacak, istatistik sorunlarını ayıracak ve körlemesine indeks eklemeden önce hangi kanıta bakmanız gerektiğini öğreneceksiniz.

TürkDB açısından ürünleşme notu

Bu bölüm, TürkDB’nin ilgili problemi hangi ürün ilkeleri ve kontrol noktalarıyla ele alacağını anlatır. Kapsam, gerçek iş yükü ve ihtiyaçla birlikte netleşir.

TürkDB PostgreSQL tarafında yavaş sorgu, metrik ve bakım sinyallerini aynı bağlamda görünür kılmayı hedefler. Planner kararı yine PostgreSQL’in EXPLAIN çıktısıyla anlaşılır; platform bu kanıta erişimi kolaylaştırmalıdır.

Planner tahminle karar verir

PostgreSQL her sorguda tüm olasılıkları gerçek veride deneyip en hızlısını seçmez. İstatistiklere, tablo büyüklüğüne, indeks bilgisine ve maliyet ayarlarına bakarak tahmin yapar. Tahmin yanlışsa plan da yanlış görünebilir.

Bu yüzden EXPLAIN çıktısında en önemli sinyallerden biri estimated rows ile actual rows farkıdır. Tahmin 100 satır, gerçek 2 milyon satırsa planner başka bir dünya varsaymış demektir.

  • İstatistikler eskiyse ANALYZE gerekir.
  • Veri dağılımı çok dengesizse varsayılan istatistik hedefi yetmeyebilir.
  • Fonksiyonlu WHERE koşulları indeks kullanımını zorlaştırabilir.
  • Tenant bazlı uçurumlar plan kararlılığını bozabilir.

EXPLAIN’i süre kadar tahmin farkı için okuyun

EXPLAIN ANALYZE BUFFERS çıktısı yalnızca sorgu kaç milisaniye sürdü diye okunmamalıdır. Hangi adım kaç satır bekledi, kaç satır gördü, diskten mi bellekten mi okudu ve en çok zaman nerede harcandı soruları daha değerlidir.

Bu okuma yapılmadan indeks eklemek bazen sorunu çözmez, sadece yazma maliyetini artırır.

Planı kanıtla okuma

postgresql-explain-buffers.sql
explain (analyze, buffers, verbose)
select *
from orders
where tenant_id = 42
  and status = 'paid'
  and created_at >= now() - interval '7 days'
order by created_at desc
limit 50;

İstatistikleri tazelemek bazen indeksten önce gelir

Tabloya çok veri eklendiyse veya dağılım değiştiyse planner hâlâ eski dünyaya göre karar veriyor olabilir. Bu durumda önce ANALYZE çalıştırmak ve autovacuum/analyze ayarlarının yeterli olup olmadığını kontrol etmek gerekir.

Çok dengesiz kolonlarda daha yüksek statistics target gerekebilir. Örneğin status alanında kayıtların yüzde 99’u paid, yüzde 1’i failed ise varsayılan örneklem bazı ayrımları yeterince iyi yakalayamayabilir.

İstatistik kontrolü

postgresql-statistics.sql
analyze orders;

select attname, n_distinct, most_common_vals, most_common_freqs
from pg_stats
where schemaname = 'public'
  and tablename = 'orders'
  and attname in ('tenant_id', 'status');

Planı zorlamak yerine sorguyu anlatılır hale getirin

PostgreSQL’de planı zorla değiştirmeye çalışmak yerine çoğu zaman sorguyu ve indeksleri planner’ın anlayacağı hale getirmek daha sağlıklıdır. Fonksiyonlu filtreleri sadeleştirmek, doğru composite index kurmak ve gereksiz SELECT * kullanımını azaltmak işe yarar.

En iyi performans iyileştirmesi, sorgunun gerçek kullanım desenini bilen uygulama ekibiyle veritabanı çıktısını aynı masaya koyduğunuzda çıkar.

Devam etmek istersen

Sorunu motor bazında derinleştirin

Benzer belirtiler farklı motorlarda farklı nedenlere dayanır; yayınlanan tüm rehberleri ana sayfadan takip edebilirsiniz.

Tüm makaleler