Soalan klasik yang dibawa oleh pembangun kepada DBA atau pemilik perniagaannya kepada perunding PostgreSQL hampir selalu berbunyi sama: "Mengapakah permintaan mengambil masa yang lama untuk disiapkan pada pangkalan data?"
Set sebab tradisional:
- algoritma yang tidak cekap
apabila anda memutuskan untuk MENYERTAI beberapa CTE dalam beberapa puluh ribu rekod - statistik lapuk
jika taburan sebenar data dalam jadual sudah sangat berbeza daripada yang dikumpul oleh ANALYZE kali terakhir - "palam" pada sumber
dan tiada lagi kuasa pengkomputeran khusus CPU yang mencukupi, memori gigabait sentiasa dipam, atau cakera tidak dapat bersaing dengan semua "kehendak" pangkalan data - menyekat daripada proses bersaing
Dan jika penyekatan agak sukar untuk ditangkap dan dianalisis, maka untuk semua perkara lain yang kami perlukan pelan pertanyaan, yang boleh diperolehi menggunakan
Tetapi, seperti yang dinyatakan dalam dokumentasi yang sama,
"Memahami rancangan adalah satu seni, dan untuk menguasainya memerlukan pengalaman tertentu..."
Tetapi anda boleh melakukannya tanpanya jika anda menggunakan alat yang betul!
Apakah rupa rancangan pertanyaan biasanya? Sesuatu seperti itu:
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
atau seperti ini:
"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"
Tetapi membaca pelan dalam teks "dari helaian" adalah sangat sukar dan tidak jelas:
- dipaparkan dalam nod jumlah dengan sumber subpokok
iaitu, untuk memahami berapa lama masa yang diambil untuk melaksanakan nod tertentu, atau berapa banyak bacaan dari jadual ini membawa data dari cakera, anda perlu menolak satu daripada yang lain. - masa nod diperlukan darab dengan gelung
ya, penolakan bukanlah operasi yang paling kompleks yang mesti dilakukan "di kepala" - selepas semua, masa pelaksanaan ditunjukkan sebagai purata untuk satu pelaksanaan nod, dan mungkin terdapat ratusan daripadanya - baik, dan semua ini bersama-sama menghalang kita daripada menjawab soalan utama - jadi siapa "pautan paling lemah"?
Apabila kami cuba menerangkan semua ini kepada beberapa ratus pembangun kami, kami menyedari bahawa dari luar ia kelihatan seperti ini:
Dan itu bermakna kita perlu...
Alat
Di dalamnya kami cuba mengumpul semua mekanik utama yang membantu memahami "siapa yang harus dipersalahkan dan apa yang perlu dilakukan" mengikut rancangan dan permintaan. Baiklah, dan kongsi sebahagian daripada pengalaman anda dengan komuniti.
Temui dan gunakan -
Keterlihatan rancangan
Adakah mudah untuk memahami rancangan itu apabila ia kelihatan seperti ini?
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
Tidak betul.
Tetapi seperti ini, dalam bentuk ringkasanapabila penunjuk utama dipisahkan, ia lebih jelas:
Tetapi jika rancangan itu lebih rumit, dia akan datang untuk menyelamatkan taburan masa piechart oleh nod:
Nah, untuk pilihan yang paling sukar dia tergesa-gesa untuk membantu carta kemajuan:
Sebagai contoh, terdapat situasi yang agak tidak remeh apabila rancangan mungkin mempunyai lebih daripada satu punca sebenar:
Petunjuk struktur
Nah, jika keseluruhan struktur pelan dan bintik-bintik sakitnya sudah dibentangkan dan kelihatan, mengapa tidak menyerlahkannya kepada pembangun dan menerangkannya dalam "bahasa Rusia"?
Kami telah mengumpulkan beberapa dozen templat pengesyoran sedemikian.
Pemprofil pertanyaan baris demi baris
Sekarang, jika anda meletakkan pertanyaan asal pada pelan yang dianalisis, anda boleh melihat berapa banyak masa yang dibelanjakan untuk setiap pernyataan individu - seperti ini:
...atau pun seperti ini:
Menggantikan parameter ke dalam permintaan
Jika anda "melampirkan" bukan sahaja permintaan kepada pelan, tetapi juga parameternya dari baris DETAIL log, anda juga boleh menyalinnya dalam salah satu pilihan:
- dengan penggantian nilai dalam permintaan
untuk pelaksanaan langsung di pangkalan anda dan pemprofilan selanjutnyaSELECT 'const', 'param'::text;
- dengan penggantian nilai melalui PREPARE/EXECUTE
untuk meniru kerja penjadual, apabila bahagian parametrik boleh diabaikan - sebagai contoh, apabila bekerja pada jadual partitionDEALLOCATE ALL; PREPARE q(text) AS SELECT 'const', $1::text; EXECUTE q('param'::text);
Arkib rancangan
Tampal, analisis, kongsi dengan rakan sekerja! Pelan akan kekal diarkibkan dan anda boleh kembali kepadanya kemudian:
Tetapi jika anda tidak mahu orang lain melihat rancangan anda, jangan lupa tandai kotak "jangan terbitkan dalam arkib".
Dalam artikel berikut saya akan bercakap tentang kesukaran dan keputusan yang timbul semasa menganalisis rancangan.
Sumber: www.habr.com