Bagaimana cara mengetahui sejauh mana query PostgreSQL saya?

35

Saya punya ide yang cukup baik tentang berapa baris SELECT saya ... KE query sebenarnya akan diproses (misalnya saya tahu berapa banyak yang akan terwujud).

Saya mengerti Postgres tidak akan memberi tahu saya persentase kelengkapan, apakah ada cara (terkubur dalam-dalam pada log, tabel sistem, atau lainnya) bahwa saya dapat mengetahui berapa banyak baris yang telah dipompa ke tabel tujuan atau telah dibaca oleh permintaan SELECT ?

Mark Elliot
sumber

Jawaban:

33

Seperti yang disebutkan oleh Daniel Vérité, sepertinya tidak ada solusi generik. Saat memuat data ke dalam tabel dari file, teknik berikut ini dapat digunakan untuk mendapatkan kemajuan pemuatan.

Baris kemajuan konsol perintah COPY

Buat tabel kosong.

CREATE TABLE mytest (n int);

Buat file data dengan 10 juta baris untuk dimuat ke dalam tabel.

$ seq 10000000 > /tmp/data.txt

Memuat data dari file ke dalam tabel dan menampilkan bilah kemajuan.

$ pv /tmp/data.txt | psql -c "COPY mytest FROM STDIN;"

Demo

masukkan deskripsi gambar di sini

Bagaimana ini bekerja?

Dengan menggunakan opsi salin perintah STDIN kita dapat memasukkan data untuk operasi salin dari proses lain. Perintah pv akan menampilkan file dan melacak progresnya yang menampilkan bilah progres, ETA, total waktu yang berlalu dan kecepatan transfer data.

SALIN perintah bilah kemajuan grafis

Dengan menggunakan teknik umum yang sama, kami dapat menampilkan bilah kemajuan dalam aplikasi grafis atau aplikasi berbasis web. Menggunakan python misalnya modul psycopg2 memungkinkan Anda memanggil perintah salin dengan objek file yang Anda pilih. Anda kemudian dapat melacak berapa banyak objek file Anda telah dibaca dan menampilkan bilah kemajuan.

Marwan Alsabbagh
sumber
2
Saya tidak menemukan pvperintah sebelumnya, dan itu tidak diinstal pada server Debian saya secara default, tetapi itu dalam repo. Deskripsi mengatakan "pv (Penampil Pipa) dapat dimasukkan ke dalam pipa normal antara dua proses untuk memberikan indikasi visual tentang seberapa cepat data melewati". Perintah yang sangat berguna!
Richard Turner
27

Tampaknya tidak ada metode umum yang didukung, tetapi ada beberapa trik yang dapat digunakan dalam konteks terbatas untuk mengevaluasi kemajuan permintaan individu. Ini beberapa di antaranya.

Urutan

Ketika kueri SELECT atau UPDATE menyertakan nextval(sequence_name), atau INSERT memiliki kolom tujuan nextvalsebagai default, nilai urutan saat ini dapat berulang kali ditanyai di sesi lain dengan SELECT sequence_name.last_value. Ini berfungsi karena urutan tidak dibatasi oleh transaksi. Ketika rencana eksekusi sedemikian rupa sehingga urutannya meningkat secara linear selama permintaan, itu dapat digunakan sebagai indikator kemajuan.

pgstattuple

The pgstattuple modul contrib menyediakan fungsi yang dapat mengintip secara langsung di halaman data. Tampaknya ketika tupel dimasukkan ke dalam tabel kosong dan belum dikomit, mereka dihitung di dead_tuple_countbidang dari pgstattuplefungsi.

Demo dengan 9.1: buat tabel kosong

CREATE TABLE tt AS (n numeric);

Mari kita masukkan baris 10M ke dalamnya:

INSERT INTO tt SELECT * FROM random() from generate_series(1,10000000);

Di sesi lain, periksa pgstattuple setiap detik selama memasukkan:

$ while true;
   do psql -Atc "select dead_tuple_count from pgstattuple('tt')";
   sleep 1;
  done

Hasil:

0
69005
520035
1013430
1492210
1990415
2224625
2772040
3314460
3928660
4317345
4743770
5379430
6080950
6522915
7190395
7953705
8747725
9242045
0

Itu jatuh kembali ke 0 ketika memasukkan selesai (semua tupel menjadi terlihat dan hidup).

Trik ini juga dapat digunakan ketika tabel tidak baru dibuat, tetapi inisial dead_tuple_countcenderung memiliki nilai tidak nol dan juga dapat berubah secara bersamaan jika aktivitas penulisan lain seperti autovacuum sedang berlangsung (mungkin? Tidak yakin pada tingkat berapa concurrency yang diharapkan dengan autovacuum).

Namun itu tidak dapat digunakan jika tabel dibuat oleh pernyataan itu sendiri ( CREATE TABLE ... AS SELECTatau SELECT * INTO newtable), karena pembuatannya ditransaksikan. Solusinya adalah membuat tabel tanpa baris (tambahkan LIMIT 0) dan isi di transaksi berikutnya.

Catatan yang pgstattupletidak datang gratis: ini memindai seluruh tabel di setiap panggilan. Juga terbatas untuk pengguna super.

Penghitung khusus

Dalam blog Pavel Stehule, ia menyediakan fungsi penghitung yang diimplementasikan dalam C yang menimbulkan PEMBERITAHUAN pada jumlah eksekusi yang ditentukan. Anda harus menggabungkan fungsi dengan kueri untuk membiarkan eksekutor memanggilnya. Pemberitahuan dikirim selama permintaan dan mereka tidak perlu sesi terpisah, hanya klien SQL yang menampilkannya ( psqlmenjadi kandidat yang jelas).

Contoh INSERT INTO yang dikerjakan ulang untuk menyampaikan pemberitahuan:

/* transformation */
INSERT INTO destination_table
   SELECT (r).*
  FROM (SELECT counter(to_destination_table(_source), 1000, true) r
           FROM source _source) x

Pertanyaan terkait tentang stackoverflow, untuk fungsi:
Bagaimana melaporkan kemajuan dari fungsi PostgreSQL yang sudah berjalan lama ke klien

Opsi masa depan?

Pada Mei 2017, ada tambalan yang menjanjikan yang dikirimkan ke komunitas pengembang: [PATCH v2] Perintah kemajuan untuk memantau perkembangan permintaan SQL yang sudah berjalan lama

yang mungkin berakhir sebagai solusi umum di PostgreSQL 11 atau lebih baru. Pengguna yang merasa ingin berpartisipasi dalam fitur yang sedang berjalan mungkin menerapkan versi tambalan terbaru dan mencoba PROGRESSperintah yang diusulkan .

Daniel Vérité
sumber
3

Hingga fungsionalitas laporan kemajuan tidak diperpanjang, seperti yang disebutkan @AmirAliAkbari dalam jawabannya, berikut adalah solusi tingkat OS.

Ini hanya berfungsi pada Linux, tetapi mungkin ada solusi serupa yang mudah googlable untuk sistem operasi apa pun.

Keuntungan terbesar dan juga kerugian dari PostgreSQL, bahwa semua backend-nya adalah proses single-threaded sederhana, menggunakan lseek(), read()dan write()untuk memanipulasi file tabel mereka, sementara mereka berinteraksi pada mem dan kunci bersama.

Hasil ini, semua proses backendnya bekerja selalu pada satu permintaan, yang dapat dengan mudah ditemukan, dan mudah straced.

Pertama, Anda dapat melihat PID backend dari SELECT * FROM pg_stat_activity;:

29805270 | dbname  | 20019 |    16384 | username  |                  |             |                 |          -1 | 2018-09-19 21:31:57.68234+02  | 2018-09-19 21:31:59.435376+02 | 2018-09-\
20 00:34:30.892382+02 | 2018-09-20 00:34:30.892386+02 | Client          | ClientRead | active              |       92778 |        92778 |  INSERT INTO ...something...

Kolom ketiga adalah pid. Dalam PostgreSQL, itu sama dengan proses Linux pid dari backend.

Selanjutnya, Anda dapat meng-strace-nya, misalnya dengan a strace -p 20019 -s 8192: ( -s 8192berguna karena postgresql bekerja dengan blok panjang 8192 byte).

sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
recvfrom(10, "Q\0\0\1\267 INSERT <removed by @peterh>", 8192, 0, NULL, NULL) = 440
sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
lseek(298, 343634345)...
read(298, "<block data which was read in>"....
write(298, "<block data which was written out>"...

Artinya:

  • sendtoterjadi jika backend menjawab sesuatu kepada klien. Dalam contoh, ini menjawab hasil dari INSERTkueri.
  • recvfromterjadi jika backend mendapatkan sesuatu dari klien. Ini biasanya kueri baru, dalam contoh, lagi INSERT.
  • lseek terjadi jika backend beralih posisi dalam file tabel.
  • read terjadi jika backend membaca blok dari file tabel.
  • write terjadi jika backend menulis blok ke file tabel.

Dalam kasus readdan write, Anda juga bisa melihat konten dari blok itu di tabel. Ini bisa sangat membantu untuk memahami, apa yang dilakukannya dan di mana itu.

Dalam kasus ini recvfrom, Anda bisa melihat permintaan aktual apa yang didapat backend.

peterh mengatakan mengembalikan Monica
sumber
2

Seperti yang dikatakan dalam jawaban lain, saat ini tidak ada cara langsung untuk melaporkan kemajuan secara umum.

PostgreSQL memiliki kemampuan untuk melaporkan perkembangan perintah tertentu selama eksekusi perintah. Saat ini, satu-satunya perintah yang mendukung pelaporan kemajuan adalah VACUUM. Ini dapat diperluas di masa depan.

Namun, mulai dari 9.6, setiap kali VACUUMberjalan, pg_stat_progress_vacuumtampilan akan berisi satu baris untuk setiap backend (termasuk proses pekerja autovacuum) yang saat ini sedang menyedot debu. Rincian lebih lanjut tentang pg_stat_progress_vacuumdapat ditemukan dalam dokumentasi: 27.4 Pelaporan Kemajuan .

Amir Ali Akbari
sumber