Trong trường hợp đơn giản nhất, khi chúng tôi chèn một hàng mới vào một bảng (và các giao dịch cam kết), nó sẽ hiển thị cho tất cả các giao dịch tiếp theo. Xem xmax
là 0 trong ví dụ này:
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
Khi chúng tôi cập nhật nó (vì cờ được đặt FALSE
ngẫu nhiên), nó sẽ thay đổi một chút:
UPDATE vis SET is_active = TRUE;
SELECT ctid, xmin, xmax, * FROM vis;
ctid │ xmin │ xmax │ id │ is_active
──────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │ 0 │ 1 │ t
Theo mô hình MVCC mà PostgreSQL sử dụng, một hàng vật lý mới đã được viết và hàng cũ bị vô hiệu (điều này có thể được nhìn thấy từ ctid
). Giao dịch mới vẫn hiển thị cho tất cả các giao dịch tiếp theo.
Bây giờ có một điều thú vị xảy ra khi chúng ta quay lại 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
Phiên bản hàng vẫn giữ nguyên, nhưng bây giờ xmax
được đặt thành một cái gì đó. Mặc dù vậy, các giao dịch tiếp theo có thể thấy hàng này (nếu không thay đổi).
Sau khi đọc một chút về điều này, bạn có thể tìm ra một vài điều về khả năng hiển thị hàng. Có bản đồ hiển thị , nhưng nó chỉ cho biết nếu toàn bộ trang có thể nhìn thấy - nó chắc chắn không hoạt động ở cấp độ hàng (tuple). Sau đó, có nhật ký cam kết (aka clog
) - nhưng làm thế nào Postgres tìm ra nếu nó phải truy cập nó?
Tôi quyết định xem xét các bit thông tin để tìm hiểu mức độ hiển thị thực sự hoạt động. Để xem chúng, cách dễ nhất là sử dụng phần mở rộng pageinspect . Để tìm ra bit nào được đặt, tôi đã tạo một bảng để lưu trữ chúng:
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));
Sau đó kiểm tra những gì bên trong vis
bảng của tôi - lưu ý pageinspect
hiển thị nội dung vật lý của heap, vì vậy không chỉ các hàng hiển thị được trả về:
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
Điều tôi hiểu từ bên trên là phiên bản đầu tiên xuất hiện với giao dịch 2699, sau đó được thay thế thành công bằng phiên bản mới vào lúc 2700.
Sau đó, phiên bản tiếp theo, tồn tại từ năm 2700, đã có một nỗ lực quay trở lại UPDATE
vào năm 2702, được nhìn thấy từ năm 2702 HEAP_XMAX_INVALID
.
Người cuối cùng không bao giờ thực sự được sinh ra, như thể hiện bởi HEAP_XMIN_INVALID
.
Vì vậy, đoán từ trên, trường hợp đầu tiên và cuối cùng là rõ ràng - chúng không còn hiển thị nữa đối với giao dịch 2703 trở lên.
Cái thứ hai phải được tra cứu ở đâu đó - tôi cho rằng đó là nhật ký cam kết, aka clog
.
Để làm phức tạp thêm các vấn đề, một UPDATE
kết quả tiếp theo sau:
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
Ở đây tôi thấy đã có hai ứng cử viên có thể nhìn thấy. Vì vậy, cuối cùng, đây là câu hỏi của tôi:
- Có phải giả định của tôi rằng đó
clog
là nơi để xem xét để xác định khả năng hiển thị trong những trường hợp này? - Những cờ nào (hoặc kết hợp các cờ) cho hệ thống truy cập
clog
? - Có cách nào để kiểm tra những gì bên trong
clog
? Có đề cập vềclog
tham nhũng trong các phiên bản trước của Postgres và một gợi ý rằng người ta có thể xây dựng một tệp giả mạo bằng tay. Thông tin này sẽ giúp rất nhiều với nó.