Dalam kasus paling sederhana, ketika kita memasukkan baris baru ke dalam tabel (dan transaksi dilakukan), itu akan terlihat oleh semua transaksi selanjutnya. Lihat xmax
menjadi 0 dalam contoh ini:
CREATE TABLE vis (
id serial,
is_active boolean
);
INSERT INTO vis (is_active) VALUES (FALSE);
SELECT ctid, xmin, xmax, * FROM vis;
ctid │xmin │ xmax │ id │ is_active
───────┼─────┼──────┼────┼───────────
(0,1) │2699 │ 0 │ 1 │ f
Ketika kami memperbaruinya (karena bendera disetel FALSE
secara tidak sengaja), itu sedikit berubah:
UPDATE vis SET is_active = TRUE;
SELECT ctid, xmin, xmax, * FROM vis;
ctid │ xmin │ xmax │ id │ is_active
──────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │ 0 │ 1 │ t
Menurut model MVCC yang digunakan PostgreSQL, baris fisik baru ditulis dan yang lama tidak valid (ini bisa dilihat dari ctid
). Yang baru masih terlihat oleh semua transaksi selanjutnya.
Sekarang ada hal menarik yang terjadi ketika kita memutar kembali UPDATE
:
BEGIN;
UPDATE vis SET is_active = TRUE;
ROLLBACK;
SELECT ctid, xmin, xmax, * FROM vis;
ctid │ xmin │ xmax │ id │ is_active
───────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │ 2702 │ 1 │ t
Versi baris tetap sama, tetapi sekarang xmax
diatur ke sesuatu. Meskipun demikian, transaksi selanjutnya dapat melihat baris ini (jika tidak berubah).
Setelah membaca sedikit tentang ini, Anda dapat mengetahui beberapa hal tentang visibilitas baris. Ada peta visibilitas , tetapi hanya memberitahu jika seluruh halaman terlihat - itu pasti tidak bekerja pada level baris (tuple). Lalu ada log komit (alias clog
) - tetapi bagaimana Postgres mengetahui jika harus mengunjunginya?
Saya memutuskan untuk melihat bit infomask untuk mengetahui bagaimana visibilitas sebenarnya bekerja. Untuk melihatnya, cara termudah adalah dengan menggunakan ekstensiinspeksi halaman . Untuk mengetahui bit mana yang diset, saya membuat tabel untuk menyimpannya:
CREATE TABLE infomask (
i_flag text,
i_bits bit(16)
);
INSERT INTO infomask
VALUES
('HEAP_HASNULL', x'0001'::bit(16)),
('HEAP_HASVARWIDTH', x'0002'::bit(16)),
('HEAP_HASEXTERNAL', x'0004'::bit(16)),
('HEAP_HASOID', x'0008'::bit(16)),
('HEAP_XMAX_KEYSHR_LOCK', x'0010'::bit(16)),
('HEAP_COMBOCID', x'0020'::bit(16)),
('HEAP_XMAX_EXCL_LOCK', x'0040'::bit(16)),
('HEAP_XMAX_LOCK_ONLY', x'0080'::bit(16)),
('HEAP_XMIN_COMMITTED', x'0100'::bit(16)),
('HEAP_XMIN_INVALID', x'0200'::bit(16)),
('HEAP_XMAX_COMMITTED', x'0400'::bit(16)),
('HEAP_XMAX_INVALID', x'0800'::bit(16)),
('HEAP_XMAX_IS_MULTI', x'1000'::bit(16)),
('HEAP_UPDATED', x'2000'::bit(16)),
('HEAP_MOVED_OFF', x'4000'::bit(16)),
('HEAP_MOVED_IN', x'8000'::bit(16)),
('HEAP_XACT_MASK', x'FFF0'::bit(16));
Kemudian periksa apa yang ada di dalam vis
meja saya - catatan yang pageinspect
menunjukkan isi fisik tumpukan, jadi tidak hanya baris yang terlihat dikembalikan:
SELECT t_xmin, t_xmax, string_agg(i_flag, ', ') FILTER (WHERE (t_infomask::bit(16) & i_bits)::integer::boolean)
FROM heap_page_items(get_raw_page('vis', 0)),
infomask
GROUP BY t_xmin, t_xmax;
t_xmin │ t_xmax │ string_agg
────────┼────────┼──────────────────────────────────────────────────────
2699 │ 2700 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
2700 │ 2702 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_INVALID, HEAP_UPDATED
2702 │ 0 │ HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
Apa yang saya mengerti dari di atas adalah bahwa versi pertama dihidupkan dengan transaksi 2699, kemudian berhasil digantikan oleh versi baru di 2700.
Kemudian yang berikutnya, yang hidup sejak 2700, memiliki upaya mundur UPDATE
pada 2702, dilihat dari HEAP_XMAX_INVALID
.
Yang terakhir tidak pernah benar-benar lahir, seperti yang ditunjukkan oleh HEAP_XMIN_INVALID
.
Jadi, menebak dari yang di atas, kasus pertama dan terakhir jelas - mereka tidak terlihat lagi untuk transaksi 2703 atau lebih tinggi.
Yang kedua harus dilihat di suatu tempat - saya kira itu adalah log komit, alias clog
.
Untuk semakin memperumit masalah, UPDATE
hasil berikut dalam berikut ini:
t_xmin │ t_xmax │ string_agg
────────┼────────┼────────────────────────────────────────────────────
2699 │ 2700 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
2702 │ 0 │ HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
2703 │ 0 │ HEAP_XMAX_INVALID, HEAP_UPDATED
2700 │ 2703 │ HEAP_XMIN_COMMITTED, HEAP_UPDATED
Di sini saya melihat sudah dua kandidat yang bisa terlihat. Jadi, akhirnya, inilah pertanyaan saya:
- Apakah asumsi saya bahwa
clog
adalah tempat untuk melihat untuk menentukan visibilitas dalam kasus ini? - Bendera mana (atau kombinasi dari bendera) yang memberi tahu sistem untuk mengunjungi
clog
? - Apakah ada cara untuk memeriksa apa yang ada di dalamnya
clog
? Ada yang menyebutkan tentangclog
korupsi di versi Postgres sebelumnya dan petunjuk bahwa seseorang dapat membuat file palsu secara manual. Sepotong informasi ini akan banyak membantu.