EXPLAIN ANALYZE Okumayı Erteledim
Seq scan'i tablo küçük diye geçiştirmek

posts listesi lokalde 40 ms idi. Staging'de 80, ilk gerçek trafikte 900. Dashboard'da 'DB CPU yüksek' yazıyordu. Ben hâlâ 'tablo küçük, seq scan normal' diyordum. Küçüktü: 12 bin satır. Küçük kalmadı: 170 bine çıktı, plan değişmedi.
Hatayı index eklememek sanıyordum. Index vardı, planner onu seçmiyordu. Bunu görmek için EXPLAIN ANALYZE bakmam gerekiyordu. Bakmayı erteledim çünkü süre 'henüz kabul edilir' idi. Kabul edilir süre, yanlış planı gizler.
Planı okumadan süreye bakmak
pgAdmin'de süreyi görüp kapatmak EXPLAIN okumak değildir. Cost tahmindir, actual time gerçektir, ikisi ayrılınca ya istatistik eskidir ya da satır tahmini yanlıştır. Ben ikisine de bakmadan 'yavaş query' diye ticket açıyordum.
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT p.id, p.title, p.published_at
FROM posts p
WHERE p.status = 'published'
AND p.published_at >= TIMESTAMPTZ '2026-01-01'
ORDER BY p.published_at DESC
LIMIT 20;
Çıktı şöyleydi. IndexScan bekliyordum, Seq Scan geldi. Filter satırı 158 bin satırı eledi, 4 binini bıraktı, sonra sort. LIMIT 20, sort'un üstünde; yani 170 bin satır okunup sıralanıp kesildi.
Sort (cost=18420.12..18430.42 rows=4120) (actual time=91.201..91.208 rows=20 loops=1)
Sort Key: published_at DESC
Buffers: shared hit=1204 read=3108
-> Seq Scan on posts p (cost=0.00..18412.00 rows=4120 width=72)
(actual time=0.082..88.440 rows=4120 loops=1)
Filter: ((status = 'published'::text) AND (published_at >= ...))
Rows Removed by Filter: 158880
Planning Time: 0.214 ms
Execution Time: 92.118 ms
Seq scan'i 'tablo küçük' diye geçiştirmek
12 bin satırda seq scan ucuz olabilir. 170 binde aynı filtre status ve published_at üzerinde hâlâ seq scan ise planner index'i görmüyor veya seçmiyor. 'Tablo küçük' cümlesi, tablo büyüyünce aynı planın kalmasıyla bitiyor. Kaldı.
(status, published_at DESC) bileşik index'i ekleyince plan Index Scan + Limit oldu. actual time 92 ms'den 1.4 ms'ye indi. Bunu hissetmedim, EXPLAIN tekrar çalıştırınca gördüm. His, 170 bin satırda yalan söyler.
actual time ile cost'u karıştırmak
Cost 18 bin, actual 92 ms. Başka bir sorguda cost 200, actual 400 ms olabiliyor: parallel seq scan, yanlış n_distinct, ya da buffer'ların hepsi read. Cost'a bakıp 'ucuz' demek, cache soğukken işe yaramaz. ANALYZE olmadan EXPLAIN sadece tahmin basar.
Buffer satırını atlamak
shared hit bellekten, read diskten. 3108 read, bu listenin her soğuk çağrıda sayfayı tekrar okuması demek. Index sonrası read 40'a düştü. Süre düşmesi kısmen CPU, kısmen I/O. İkisini ayırmadan 'index büyüsü' yazmam.
- rows tahmini ile actual rows 10 kattan fazla ayrılıyorsa ANALYZE ve istatistik.
- Rows Removed by Filter yüksekse index filtreden önce kesmiyor.
- LIMIT varken Sort+Seq Scan, index'in sıra kolonunu kaçırıyor olabilirim.
Bu yazıdan sonra yavaş ticket'ına önce EXPLAIN ANALYZE yapıştırıyorum. Süre tek başına plan değil. Planı okumayı ertelemek, yanlış planı production'da kiracı yapmak.
Yorumlar
Yorumlar (0)
Yorumlar üyelere açık. Üye ol · Giriş yap