Apakah SELECT menghapus baris mati seperti VACUUM?

9

Saya mengutak-atik VACUUMdan memperhatikan beberapa perilaku tak terduga di mana SELECTbaris-baris dari sebuah meja tampaknya mengurangi pekerjaan yang VACUUMharus dilakukan sesudahnya.

Data Uji

Catatan: autovacuum dinonaktifkan

CREATE TABLE numbers (num bigint);
ALTER TABLE numbers SET (
  autovacuum_enabled = 'f',
  toast.autovacuum_enabled = 'f'
);

INSERT INTO numbers SELECT generate_series(1, 5000);

Percobaan 1

Sekarang kami menjalankan pembaruan di semua baris,

UPDATE numbers SET num = 0;

Dan ketika kita berlari VACUUM (VERBOSE) numbers;kita dapatkan,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 5000 row versions in 23 pages
INFO:  "numbers": found 5000 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6585
There were 0 unused item pointers.

Percobaan 2

Sekarang kita mengeluarkan yang lain UPDATE, tapi kali ini kita tambahkan SELECTsesudahnya,

UPDATE numbers SET num = 1;
SELECT * FROM numbers;

Dan ketika kita berlari VACUUM (VERBOSE) numbers;kita dapatkan,

INFO:  vacuuming "public.numbers"
INFO:  "numbers": removed 56 row versions in 22 pages
INFO:  "numbers": found 56 removable, 5000 nonremovable row versions in 45 out of 45 pages
DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 6586
There were 56 unused item pointers.

Apa sebenarnya yang terjadi di sini? Mengapa versi kedua saya jalankan, setelah SELECTmenghapus tupel mati dari halaman yang dikunjungi, cukup seperti VACUUMitu?

Saya menjalankan Postgres 11.3 di macOS 10.14.5.

rafbm
sumber
2
Klien apa yang Anda gunakan untuk menjalankan perintah Anda? Apakah autocommit diaktifkan di dalamnya?
mustaccio
2
Saya akan menghapus pertanyaan "Apakah tabel VACUUM pada dasarnya hanya SELECT * FROM table under the hood?" (tidak) Saya pikir itu tindak lanjut yang baik, jawabannya di sini adalah sederhana bahwa SELECT dapat menghapus baris mati, dan itu berbagi dengan persamaan dengan VACUUM. Bagaimana mereka berbeda akan menjadi percakapan yang sangat lengkap tentang rollover XID, dan banyak hal lainnya. Pertanyaan itu pada dasarnya adalah "Apa hal-hal lain yang dilakukan penyedot selain menghilangkan baris mati." (Yang akan menjadi agak kabur)
Evan Carroll
@ mustaccio Saya melakukan tes ini dengan skrip Ruby menggunakan ActiveRecord, yang menggunakan permata PG di bawah tenda. Saya percaya bahwa autocommit diaktifkan secara default karena Anda tidak perlu mengeluarkan COMMIT, kecuali BEGIN digunakan secara eksplisit.
rafbm

Jawaban:

5

Dari posting ini di / r / PostgreSQL ke jawaban oleh Laurenz Albe tampaknya pembaruan Heap Only Tuples (HOT) mungkin bertanggung jawab. Dari deskripsi pembaruan HOT disrc/backend/access/heap/README.HOT

Secara efektif, reklamasi ruang terjadi selama pengambilan tuple ketika halaman hampir penuh (<10% gratis) dan kunci pembersihan buffer dapat diperoleh. Ini berarti bahwa UPDATE,, DELETEdan SELECTdapat memicu reklamasi ruang, tetapi seringkali tidak selama INSERT ... VALUESkarena tidak mengambil baris.

Kutipan tidak ada dalam jawaban asli, tetapi sisanya adalah kutipan,

Untuk mendukung atau membantah teori ini, jalankan kueri berikut:

SELECT n_tup_upd, n_tup_hot_upd
FROM pg_stat_user_tables
WHERE schemaname = 'public' AND relname = 'TABLE_NAME';

Jika n_tup_hot_updlebih besar dari nol, kami punya kasing.

Evan Carroll
sumber
Sekarang kita bicara. +1
mustaccio
HOT sepertinya menjadi penjelasan yang bagus. Jika I CREATE INDEX idx_numbers ON numbers USING btree (num), output VACUUM berubah menjadi INFO: "numbers": removed 5000 row versions in 45 pages. Namun perhatikan bahwa dalam skenario indeks-kurang, n_tup_hot_updselalu 0, antara UPDATE dan SELECT dan antara SELECT dan VACUUM. Saya juga memastikan untuk menjalankan SELECT pg_sleep(10)antara setiap pernyataan sehingga statistik terbaru (saya melihat seq_scan: 2, satu untuk UPDATE dan satu untuk SELECT).
rafbm
Apakah pilih menghasilkan WAL dalam kasus ini? Saya mendapat kesan bahwa pemilih tidak menghasilkan WAL sama sekali. Jika ya, ini berarti penghapusan baris mati akan disebarkan ke setiap budak. Jika tidak, ini berarti masih diperlukan penyedotan pada budak. Itu juga berarti bahwa tuan dan budak tidak sedikit identik. Hmm, mungkin saya perlu melakukan riset dan memposting pertanyaan dan / atau jawaban atau dua.
Colin 't Hart
1

Dalam kasus khusus dari tabel yang tidak diindeks, ya, SELECT dapat melakukan pekerjaan yang sama dengan VACUUM (sejauh menghilangkan baris mati yang bersangkutan).

jjanes
sumber
3
Bisakah Anda menambahkan penjelasan?
Laurenz Albe