PostgreSQL'de Yavaş Sorgu: EXPLAIN ANALYZE Okuma Rehberi

Haberci

SEO UZMANI
Yönetici
Katılım
21 May 2023
Mesajlar
496
Tepki
17
Puan
18
Yavaş bir SQL görünce ilk refleks çoğu zaman indeks eklemek oluyor. Oysa planın seçtiği tarama türünü, kaç satır beklediğini ve gerçekte kaç satırla karşılaştığını görmeden eklenen indeks hiç kullanılmayabilir; hatta yazma maliyetini artırabilir.

Plan çıktısı yukarıdan aşağı okunan düz bir log değildir. Girintiler bir ağaç oluşturur; alttaki düğümler satır üretir, üsttekiler bu satırları sıralar, birleştirir veya toplar. Aşağıdaki alanlar PostgreSQL 18’in güncel belge hattına göre ele alınıyor.



752




Önce en önemli uyarı: ANALYZE sorguyu çalıştırır​


EXPLAIN yalnız planlayıcının seçtiği planı gösterir. EXPLAIN ANALYZE ise aynı sorguyu gerçekten yürütür ve gerçek süre ile satır sayılarını plana ekler.

Üretimde durup okuyun' Alıntı:
Buradaki ANALYZE, yalnız istatistiklere bakmak değildir. SELECT çalışır; INSERT, UPDATE, DELETE veya MERGE ise veri değiştirme işini gerçekten yapar.

İlk bakış için yan etkisiz olan düz planla başlayın:

Kod:
EXPLAIN (COSTS, VERBOSE)
SELECT * FROM siparisler WHERE musteri_id = 42;

Gerçek yürütme bilgisi gerekiyorsa temsilî veri bulunan kontrollü ortamda:

Kod:
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM siparisler WHERE musteri_id = 42;

PostgreSQL’in 18 sürümü EXPLAIN belgesi, veri değiştiren bir komutu tablo değişikliğini kalıcılaştırmadan incelemek için şu işlem bloğunu gösterir:

Kod:
BEGIN;
EXPLAIN (ANALYZE, BUFFERS)
UPDATE siparisler SET durum = 'arsiv' WHERE id = 42;
ROLLBACK;

ROLLBACK tablo değişikliğini geri alır; sorgunun çalışırken tükettiği CPU ve I/O’yu, aldığı kilitleri veya diğer oturumlara yaşattığı beklemeyi geriye sarmaz. Önce test/staging ortamı, sonra temsilî parametre ve uygun bakım aralığı düşünülmelidir. Uzun sorgular için oturum düzeyinde makul statement_timeout ve lock_timeout sınırları ayrıca belirlenebilir.

Planı girintili bir ağaç olarak okuyun​


En derindeki tarama düğümü tablo veya indeksten satır üretir. Ok işaretiyle bir üst düğüme verilen bu satırlar filtre, sort, aggregate ya da join işleminden geçer. Bu nedenle yalnız ilk satıra bakıp “Nested Loop kötü” veya “Seq Scan kötü” demek yeterli değildir.

Pratik okuma sırasında önce şunları bulun:

  • En alttaki scan düğümleri hangi tabloya erişiyor?
  • Index Cond ile Filter ayrımı nerede? Filtreye gelene kadar kaç satır taşınmış?
  • Tahmin edilen rows ile gerçek rows birbirine yakın mı?
  • Bir düğüm kaç kez çalışmış; loops değeri kaç?
  • Sort veya hash işlemi bellekte mi kalmış, geçici diske taşmış mı?

Üst düğümün süresi ve buffer sayıları çocuklarının işini içerebilir. Bu yüzden bütün satırlardaki süreleri veya buffer değerlerini toplayıp “toplam budur” demeyin; ağacın ilişkisini koruyarak okuyun.

Cost, actual time, rows ve loops aynı tür sayı değildir​


cost=başlangıç..toplam, planlayıcının karşılaştırma için kullandığı tahmini maliyet birimidir; milisaniye değildir. actual time=ilk_satır..son_satır ise ANALYZE sırasında ölçülen gerçek zamanı milisaniye olarak verir.

PostgreSQL 18’in resmî belgesindeki bir indeks düğümünden seçilmiş gerçek örnek şöyledir; bu forum için üretilmiş bir ölçüm değildir ve başka veri üzerinde aynı sayıların çıkması beklenmez:

Kod:
Index Scan using test_pkey on test
(cost=0.29..10.27 rows=99 width=8)
(actual time=0.009..0.025 rows=99.00 loops=1)
Buffers: shared hit=4

Bu düğümde planlayıcı 99 satır beklemiş, yürütme de ortalama 99 satır üretmiş. loops=1 olduğu için tekrar çarpanı yok. Resmî Using EXPLAIN bölümü, bir düğüm birden fazla çalıştığında actual time ve rows değerlerinin her yürütme başına ortalama olduğunu belirtir. Toplam iş için ilgili değeri loops ile birlikte düşünmek gerekir.

Örneğin actual rows=2 loops=1000 gördüğünüzde düğüm yalnız iki satırla uğraşmış sayılmaz; bin yürütmenin her birinde ortalama iki satır üretmiştir. Nested loop’un iç tarafında küçük görünen bir maliyet bu yüzden toplamda büyüyebilir.

Scan adını tek başına iyi veya kötü diye etiketlemeyin​


  • Seq Scan: Tabloyu sıralı tarar. Küçük tabloda veya satırların büyük bölümü isteniyorsa indeks aramalarından daha ucuz olabilir. Varlığı tek başına hata değildir.
  • Index Scan: Koşula uygun indeks girdilerini bulur ve gereken tablo satırlarını heap’ten alır. Az ve seçici sonuçlarda avantajlı olabilir; çok satırda dağınık heap erişimi pahalılaşabilir.
  • Bitmap Index Scan + Bitmap Heap Scan: Önce uygun satır konumlarını bir bitmap’te toplar, sonra tablo sayfalarını daha düzenli okur. Seq Scan ile tek tek Index Scan arasındaki orta seçicilikte sık görülür.
  • Index Only Scan: Gerekli sütunlar indeksten karşılanabiliyorsa tablo verisine erişimi azaltabilir. Fakat görünürlük kontrolü için heap’e gitmek gerekebilir; plandaki Heap Fetches satırı bunu anlamaya yardım eder.

PostgreSQL’in index-only scan belgesi, indeksin sorgudaki sütunları karşılamasının yanında visibility map koşulunu da açıklar. Adında “Only” geçmesi her yürütmede sıfır heap erişimi garantisi değildir.

Buffers satırı zamanın nereye gittiğini daraltır​


PostgreSQL 18’de ANALYZE, buffer bilgisini varsayılan olarak içerir; komutta BUFFERS yazmak niyeti görünür kılar. En sık karşılaşılan alanlar:

  • shared hit: Gerekli blok PostgreSQL’in paylaşılan cache’inde bulundu; bu okuma önlendi. “Maliyetsiz” demek değildir, yalnız ilgili blok için yeni bir read gerekmediğini söyler.
  • shared read: Paylaşılan tablo veya indeks bloğu cache’te hazır değildi ve okunması gerekti. İşletim sistemi cache’i nedeniyle bunu doğrudan fiziksel disk okumasıyla eşitlemeyin.
  • temp read / written: Sort, hash veya benzeri çalışma verisi geçici alana taşmış olabilir. İlgili Sort/Hash düğümü ve bellek bilgisiyle birlikte değerlendirin.
  • dirtied / written: Sorgunun değiştirdiği veya bu backend’in cache’ten yazdığı bloklar hakkında bilgi verir.

Üst düğümdeki buffer sayıları çocuk düğümlerin sayılarını da içerir ve aynı blok birden fazla erişimde sayılabilir. Soğuk ve sıcak cache koşullarındaki iki çalıştırma farklı sonuç verebilir; ölçüm koşulunu not etmeden planları karşılaştırmayın. track_io_timing açıksa I/O süreleri de görünür olabilir.

Tahmin ile gerçek satır ayrışıyorsa önce istatistiğe bakın​


Bir düğüm rows=10 beklerken gerçekte yüz bin satır üretiyorsa planlayıcı sonraki join ve scan seçimini yanlış büyüklük varsayımıyla yapmış olabilir. Böyle bir fark doğrudan “indeks eksik” hükmü değildir.

Önce şu olasılıkları ayırın:

  • Tablo yakın zamanda büyük ölçüde değişti ve istatistikler geride kaldı mı?
  • Veri dağılımı çok eğri mi; birkaç değer satırların çoğunu mu taşıyor?
  • İki sütun birbirine bağlı olduğu hâlde planlayıcı onları bağımsız mı tahmin ediyor?
  • Uygulamadaki gerçek parametre, testte kullandığınız değerden farklı seçicilikte mi?

PostgreSQL 18 ANALYZE belgesi, komutun tablo içeriği hakkında istatistik toplayıp pg_statistic içine yazdığını ve planlayıcının bunları kullandığını açıklar. Autovacuum çoğu durumda bu işi yürütür; büyük veri değişiminden sonra istatistiklerin güncel olup olmadığı kontrol edilmelidir. İstatistik toplama komutunu, EXPLAIN ANALYZE içindeki ANALYZE seçeneğiyle karıştırmayın: adları benzer, yaptıkları iş farklıdır.

Güvenli bir plan karşılaştırması aynı koşulları ister​


Bir iyileştirmeyi değerlendirmeden önce sorgu metnini, gerçekçi parametreleri, PostgreSQL sürümünü, tablo büyüklüğünü ve planı aynı kayıt altında tutun. Birinci çalışma cache’i ısıtıp ikincisini hızlandırabilir; yalnız en iyi süreyi seçmek yanıltır. EXPLAIN ANALYZE’ın kendi ölçüm yükü bulunduğunu ve sonuç satırlarını istemciye göndermediği için ağ maliyetini ölçmediğini de hesaba katın.

İlk turda şu soruya cevap aramak yeterlidir: Sorgu fazla satır mı okuyor, satır sayısını yanlış mı tahmin ediyor, aynı düğümü çok kez mi çalıştırıyor, yoksa sort/hash sırasında geçici alana mı taşıyor? Bu cevap gelmeden ayar kapatmak veya zorla scan türü seçmek sorunu saklayabilir.

Veri tabanı kavramlarını tazelemek için veri tabanı yönetimi konusuna, ölçüm ve testleri geliştirme akışına bağlamak için veri odaklı yazılım geliştirme rehberine bakabilirsiniz.

Yardım isterken sorgudaki kişisel değerleri maskeleyip planı FORMAT TEXT veya makine işleyecekse FORMAT JSON olarak paylaşın. PostgreSQL sürümü, gerçek parametrelerin seçiciliği ve tablonun yaklaşık büyüklüğü de eklendiğinde yalnız “Seq Scan gördüm” demekten çok daha hızlı yol alınır.



Dijital Dünyanıza Yön Veren Pusula
 

Ekli dosyalar

  • postgresql-explain-analyze_1000x120.jpg
    postgresql-explain-analyze_1000x120.jpg
    8.4 KB · Görüntüleme: 2
Geri
Üst