Bir geliştiricinin DBA'sına veya bir işletme sahibinin PostgreSQL danışmanına sorduğu klasik soru neredeyse her zaman aynı geliyor: “Veritabanında isteklerin tamamlanması neden bu kadar uzun sürüyor?”
Geleneksel nedenler dizisi:
- verimsiz algoritma
birkaç on binlerce kayıt üzerinden birkaç CTE'ye KATILMAYA karar verdiğinizde - eski istatistikler
Tablodaki verilerin gerçek dağılımı, ANALYZE tarafından son kez toplananlardan zaten çok farklıysa - Kaynaklara "tak"
ve CPU'nun ayrılmış bilgi işlem gücü artık yeterli değil, gigabaytlarca bellek sürekli olarak pompalanıyor veya disk, veritabanının tüm "isteklerine" ayak uyduramıyor - Kilitlemek rakip süreçlerden
Ve eğer engellemeleri yakalamak ve analiz etmek oldukça zorsa, o zaman ihtiyacımız olan her şey için sorgu planıkullanılarak elde edilebilecek
Ancak aynı belgelerde belirtildiği gibi,
“Bir planı anlamak bir sanattır ve ona hakim olmak belli bir miktar deneyim gerektirir…”
Ancak doğru aracı kullanırsanız onsuz da yapabilirsiniz!
Bir sorgu planı genellikle neye benzer? Bunun gibi bir şey:
Index Scan using pg_class_relname_nsp_index on pg_class (actual time=0.049..0.050 rows=1 loops=1)
Index Cond: (relname = $1)
Filter: (oid = $0)
Buffers: shared hit=4
InitPlan 1 (returns $0,$1)
-> Limit (actual time=0.019..0.020 rows=1 loops=1)
Buffers: shared hit=1
-> Seq Scan on pg_class pg_class_1 (actual time=0.015..0.015 rows=1 loops=1)
Filter: (relkind = 'r'::"char")
Rows Removed by Filter: 5
Buffers: shared hit=1
ya da bunun gibi:
"Append (cost=868.60..878.95 rows=2 width=233) (actual time=0.024..0.144 rows=2 loops=1)"
" Buffers: shared hit=3"
" CTE cl"
" -> Seq Scan on pg_class (cost=0.00..868.60 rows=9972 width=537) (actual time=0.016..0.042 rows=101 loops=1)"
" Buffers: shared hit=3"
" -> Limit (cost=0.00..0.10 rows=1 width=233) (actual time=0.023..0.024 rows=1 loops=1)"
" Buffers: shared hit=1"
" -> CTE Scan on cl (cost=0.00..997.20 rows=9972 width=233) (actual time=0.021..0.021 rows=1 loops=1)"
" Buffers: shared hit=1"
" -> Limit (cost=10.00..10.10 rows=1 width=233) (actual time=0.117..0.118 rows=1 loops=1)"
" Buffers: shared hit=2"
" -> CTE Scan on cl cl_1 (cost=0.00..997.20 rows=9972 width=233) (actual time=0.001..0.104 rows=101 loops=1)"
" Buffers: shared hit=2"
"Planning Time: 0.634 ms"
"Execution Time: 0.248 ms"
Ancak planı "sayfadan" metinde okumak çok zor ve belirsizdir:
- düğümde görüntülenir alt ağaç kaynaklarına göre toplam
yani, belirli bir düğümü yürütmenin ne kadar zaman aldığını veya tablodan yapılan bu okumanın diskten veriyi tam olarak ne kadar getirdiğini anlamak için birini diğerinden çıkarmanız gerekir. - düğüm zamanına ihtiyaç var döngülerle çarpma
evet, çıkarma işlemi "kafada" yapılması gereken en karmaşık işlem değildir - sonuçta yürütme süresi, bir düğümün bir yürütülmesi için ortalama olarak gösterilir ve bunlardan yüzlerce olabilir - peki, ve tüm bunlar birlikte asıl soruyu cevaplamamızı engelliyor - peki kim "en zayıf halka"?
Tüm bunları yüzlerce geliştiricimize açıklamaya çalıştığımızda dışarıdan şöyle göründüğünü fark ettik:
Bu da ihtiyacımız olduğu anlamına geliyor...
Araç
Plana ve talebe göre "kimin suçlanacağını ve ne yapılacağını" anlamaya yardımcı olacak tüm temel mekanizmaları toplamaya çalıştık. Peki, deneyiminizin bir kısmını toplulukla paylaşın.
Tanışın ve kullanın -
Planların görünürlüğü
Böyle görününce planı anlamak kolay mı?
Seq Scan on pg_class (actual time=0.009..1.304 rows=6609 loops=1)
Buffers: shared hit=263
Planning Time: 0.108 ms
Execution Time: 1.800 ms
Pek değil.
Ama bunun gibi, kısaltılmış biçimdeTemel göstergeler birbirinden ayrıldığında durum daha da netleşiyor:
Ancak plan daha karmaşıksa kurtarmaya gelecektir. pasta grafik zaman dağılımı düğümlere göre:
En zor seçenekler için yardım etmek için acele ediyor ilerleme tablosu:
Örneğin, bir planın birden fazla gerçek kökü olabileceği oldukça önemsiz durumlar vardır:
Yapısal ipuçları
Peki, planın tüm yapısı ve hassas noktaları zaten belirlenmiş ve görünürse, neden bunları geliştiriciye vurgulayıp "Rus dilinde" açıklamıyorsunuz?
Zaten birkaç düzine bu tür öneri şablonunu topladık.
Satır satır sorgu profili oluşturucu
Şimdi, orijinal sorguyu analiz edilen planın üzerine eklerseniz, her bir ifadeye ne kadar zaman harcandığını görebilirsiniz - bunun gibi bir şey:
...veya hatta şöyle:
Bir isteğin parametrelerini değiştirme
Plana yalnızca bir istek değil, aynı zamanda günlüğün DETAY satırındaki parametrelerini de "eklediyseniz", bunu seçeneklerden birine ek olarak kopyalayabilirsiniz:
- talepte değer ikamesi ile
üssünüzde doğrudan uygulama ve daha fazla profil oluşturma içinSELECT 'const', 'param'::text;
- PREPARE/EXECUTE aracılığıyla değer ikamesi ile
Parametrik kısmın göz ardı edilebildiği durumlarda (örneğin bölümlenmiş tablolar üzerinde çalışırken) zamanlayıcının çalışmasını taklit etmek içinDEALLOCATE ALL; PREPARE q(text) AS SELECT 'const', $1::text; EXECUTE q('param'::text);
Plan arşivi
Yapıştırın, analiz edin, iş arkadaşlarınızla paylaşın! Planlar arşivlenmiş olarak kalacak ve onlara daha sonra geri dönebileceksiniz:
Ancak planınızın başkalarının görmesini istemiyorsanız “arşivde yayınlama” kutusunu işaretlemeyi unutmayın.
Sonraki yazılarda bir planı analiz ederken ortaya çıkan zorluklardan ve kararlardan bahsedeceğim.
Kaynak: habr.com