VACUUM mengembalikan ruang disk ke sistem operasi


21

VACUUMbiasanya tidak mengembalikan ruang disk ke sistem operasi, kecuali dalam beberapa kasus khusus.
Dari dokumen:

Bentuk standar untuk VACUUMmenghapus versi baris mati dalam tabel dan indeks dan menandai ruang yang tersedia untuk digunakan kembali di masa depan. Namun, itu tidak akan mengembalikan ruang ke sistem operasi, kecuali dalam kasus khusus di mana satu atau lebih halaman di ujung tabel menjadi sepenuhnya bebas dan kunci meja eksklusif dapat dengan mudah diperoleh. Sebaliknya, VACUUM FULLsecara aktif memadatkan tabel dengan menulis versi baru lengkap dari file tabel tanpa ruang kosong. Ini meminimalkan ukuran meja, tetapi bisa memakan waktu lama. Ini juga membutuhkan ruang disk tambahan untuk salinan tabel yang baru, sampai operasi selesai.

Pertanyaannya adalah: bagaimana database ini menyatakan kapan one or more pages at the end of a table become entirely freebisa dicapai? Ini dapat dilakukan melalui VACUUM FULL, tetapi saya tidak punya cukup ruang untuk mengimplementasikannya. Jadi, apakah ada kemungkinan lain?

Jawaban:


29

Untuk mengembalikan ruang ke OS, gunakan VACUUM FULL. Sementara berada di sana, saya kira Anda lari VACUUM FULL ANALYZE. Saya mengutip manual :

FULL

Memilih vakum "penuh", yang dapat memperoleh kembali lebih banyak ruang , tetapi membutuhkan waktu lebih lama dan secara eksklusif mengunci tabel. Metode ini juga membutuhkan ruang disk tambahan, karena ia menulis salinan tabel baru dan tidak merilis salinan lama sampai operasi selesai. Biasanya ini hanya boleh digunakan ketika sejumlah besar ruang perlu direklamasi dari dalam tabel.

Penekanan berani saya.

CLUSTER mencapai itu juga, sebagai efek jaminan.

Plain VACUUMbiasanya tidak mencapai tujuan Anda ( "satu atau lebih halaman di ujung tabel sepenuhnya gratis" ). Itu tidak menyusun ulang baris dan hanya memangkas halaman kosong dari ujung fisik file ketika kesempatan muncul - seperti kutipan Anda dari instruksi manual.

Anda bisa mendapatkan halaman kosong di akhir file fisik saat Anda INSERTmenambahkan banyak baris dan DELETEsebelum tupel lainnya ditambahkan. Atau itu bisa terjadi secara kebetulan jika cukup banyak baris dihapus.

Ada juga pengaturan khusus yang mungkin mencegah VACUUM FULLdari reklamasi ruang. Lihat:

Persiapkan halaman kosong di akhir tabel untuk pengujian

Kolom sistem ctidmewakili posisi fisik suatu baris. Anda perlu memahami kolom itu:

Kita bisa bekerja dengan itu dan menyiapkan tabel dengan menghapus semua baris dari halaman terakhir:

DELETE FROM tbl t
USING (
   SELECT (split_part(ctid::text, ',', 1) || ',0)')::tid     AS min_tid
        , (split_part(ctid::text, ',', 1) || ',65535)')::tid AS max_tid
   FROM   tbl
   ORDER  BY ctid DESC
   LIMIT  1
   ) d
WHERE t.ctid BETWEEN d.min_tid AND d.max_tid;

Sekarang, halaman terakhir kosong. Ini mengabaikan menulis bersamaan. Entah Anda satu-satunya yang menulis ke meja itu atau Anda perlu mengambil kunci tulis untuk menghindari gangguan.

Kueri dioptimalkan untuk mengidentifikasi baris yang memenuhi syarat dengan cepat. Angka kedua a tidadalah indeks tuple yang disimpan sebagai tidak bertanda int2, dan 65535merupakan maksimum untuk tipe itu ( 2^16 - 1), jadi itulah batas atas yang aman.

SQL Fiddle (menggunakan kembali tabel sederhana dari kasus yang berbeda.)

Alat untuk mengukur ukuran baris / tabel:

Disk penuh

Anda perlu ruang gerak pada disk untuk semua operasi ini. Ada juga alat komunitas pg_repacksebagai pengganti VACUUM FULL/ CLUSTER. Itu menghindari kunci eksklusif tetapi membutuhkan ruang bebas untuk bekerja dengan juga. Manual:

Membutuhkan ruang disk kosong dua kali lebih besar dari tabel target dan indeks.

Sebagai upaya terakhir, Anda dapat menjalankan siklus dump / restore. Itu menghapus semua mengasapi dari tabel dan indeks juga. Pertanyaan yang terkait erat:

Jawabannya cukup radikal. Jika situasi Anda memungkinkan (tidak ada kunci asing atau referensi lain yang mencegah penghapusan baris), dan tidak ada akses bersamaan ke tabel), Anda dapat:

Membuang meja ke disk yang terhubung dari komputer jarak jauh dengan banyak ruang disk ( -auntuk --data-only):

Dari shell jauh, buang data tabel:

pg_dump -h <host_name> -p <port> -t mytbl -a mydb > db_mytbl.sql

Dalam sesi pg, TRUNCATEtabel:

-- drop all indexes and constraints here for best performance
TRUNCATE mytbl;

Dari shell jarak jauh, pulihkan ke tabel yang sama:

psql -h <host_name> -p <port> mydb -f db_mytbl.sql
-- recreate all indexes and constraints here

Sekarang bebas dari baris mati atau kembung.

Tapi mungkin Anda bisa memiliki yang lebih sederhana?

  • Bisakah Anda membuat cukup ruang pada disk dengan menghapus (memindahkan) file yang tidak terkait?

  • Bisakah Anda VACUUM FULLmengecilkan tabel lebih dulu, satu per satu, sehingga membebaskan ruang disk yang cukup?

  • Bisakah Anda menjalankan REINDEX TABLEatau REINDEX INDEXmembebaskan ruang disk dari indeks yang membengkak?

Apa pun yang Anda lakukan, jangan terburu-buru . Jika ragu, cadangkan semuanya ke lokasi yang aman terlebih dahulu.


Erwin, maaf, saya lupa menyebutkan bahwa saya tidak punya cukup ruang untuk vakum penuh. Memperbarui pertanyaan.
salah tentang segalanya

@Zapadlo: Saya menambahkan bab untuk pertanyaan yang diperbarui.
Erwin Brandstetter

Terima kasih atas jawaban yang komprehensif. Sebenarnya saya berpikir bahwa saya dapat menempatkan baris mati di akhir halaman db dengan pembaruan palsu, yaitu update table set field_1 = field_1, tetapi menyedot debu tabel itu setelah operasi itu gagal mengembalikan ruang kosong, ada ide?
salah tentang semuanya

@Zapadlo: Gagasan yang saya miliki sudah ada dalam jawaban. :) Saya tidak tahu alat yang dapat menyusun ulang tupel mati tanpa perlu ruang gerak yang besar pada disk. (Tidak berarti tidak mungkin ada orang di luar sana.)
Erwin Brandstetter

Mereka mengatakan alat ini melakukan trik, namun belum mencobanya: code.google.com/p/pgtoolkit/source/browse/trunk/bin/…
salah-tentang-semuanya
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.