Bisakah seseorang menjelaskan perilaku ini kepada saya? Saya menjalankan query berikut pada Postgres 9.3 yang berjalan secara native di OS X. Saya mencoba mensimulasikan beberapa perilaku di mana ukuran indeks bisa tumbuh jauh lebih besar daripada ukuran tabel, dan malah menemukan sesuatu yang bahkan lebih aneh.
CREATE TABLE test(id int);
CREATE INDEX test_idx ON test(id);
CREATE FUNCTION test_index(batch_size integer, total_batches integer) RETURNS void AS $$
DECLARE
current_id integer := 1;
BEGIN
FOR i IN 1..total_batches LOOP
INSERT INTO test VALUES (current_id);
FOR j IN 1..batch_size LOOP
UPDATE test SET id = current_id + 1 WHERE id = current_id;
current_id := current_id + 1;
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT test_index(500, 10000);
Saya membiarkan ini berjalan sekitar satu jam di mesin lokal saya, sebelum saya mulai mendapatkan peringatan masalah disk dari OS X. Saya perhatikan bahwa Postgres menyedot sekitar 10MB / s dari disk lokal saya, dan bahwa database Postgres mengkonsumsi total besar 30GB dari mesin saya. Saya akhirnya membatalkan permintaan. Bagaimanapun, Postgres tidak mengembalikan ruang disk kepada saya dan saya menanyakan database untuk statistik penggunaan dengan hasil sebagai berikut:
test=# SELECT nspname || '.' || relname AS "relation",
pg_size_pretty(pg_relation_size(C.oid)) AS "size"
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_relation_size(C.oid) DESC
LIMIT 20;
relation | size
-------------------------------+------------
public.test | 17 GB
public.test_idx | 14 GB
Namun, memilih dari tabel tidak membuahkan hasil.
test=# select * from test limit 1;
id
----
(0 rows)
Menjalankan 10.000 kumpulan 500 adalah 5.000.000 baris, yang seharusnya menghasilkan ukuran tabel / indeks yang cukup kecil (pada skala MB). Saya menduga Postgres membuat versi baru dari tabel / indeks untuk setiap INSERT / UPDATE yang terjadi dengan fungsi, tetapi ini tampaknya aneh. Seluruh fungsi dijalankan secara transaksi, dan tabel kosong untuk memulai.
Adakah pemikiran mengapa saya melihat perilaku ini?
Secara khusus, dua pertanyaan yang saya miliki adalah: mengapa ruang ini belum direklamasi oleh database dan yang kedua adalah mengapa database membutuhkan ruang sebanyak ini? 30GB tampak seperti banyak bahkan ketika menghitung MVCC