가장 간단한 경우 테이블에 새 행을 삽입하면 (및 트랜잭션 커밋) 모든 후속 트랜잭션에 표시됩니다. xmax
이 예에서 0 인 것을 참조하십시오 .
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
FALSE
실수로 플래그를 설정했기 때문에 업데이트하면 약간 변경됩니다.
UPDATE vis SET is_active = TRUE;
SELECT ctid, xmin, xmax, * FROM vis;
ctid │ xmin │ xmax │ id │ is_active
──────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │ 0 │ 1 │ t
PostgreSQL이 사용 하는 MVCC 모델 에 따르면 , 새로운 물리적 행이 작성되었고 이전 행은 무효화되었습니다 (이것은에서 볼 수 있습니다 ctid
). 새로운 거래는 여전히 모든 후속 거래에서 볼 수 있습니다.
이제 롤백 할 때 흥미로운 일이 발생합니다 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
행 버전은 동일하게 유지되지만 이제는 xmax
무언가로 설정됩니다. 그럼에도 불구하고, 후속 트랜잭션은이 (그렇지 않으면 변경되지 않은) 행을 볼 수 있습니다.
이것에 대해 조금 읽은 후에 행 가시성에 대해 몇 가지를 알아낼 수 있습니다. 거기이다 가시성 맵은 , 그러나 그것은 단지 전체 페이지가 표시되는 경우 알려줍니다 - 그것은 확실히 행 (튜플) 수준에서 작동하지 않습니다. 그런 다음 커밋 로그 (일명 clog
)가 있지만 Postgres는 방문 해야하는지 어떻게 알 수 있습니까?
가시성이 실제로 어떻게 작동하는지 파악하기 위해 infomask 비트 를 살펴보기로 결정했습니다 . 그것들을 보려면 가장 쉬운 방법은 pageinspect extension 을 사용하는 것입니다 . 어떤 비트가 설정되었는지 확인하기 위해 비트를 저장하는 테이블을 만들었습니다.
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));
그런 다음 내 vis
테이블 내부의 pageinspect
내용을 확인했습니다-힙의 실제 내용을 표시하므로 보이는 행만 반환되지는 않습니다.
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
내가 위에서 이해 한 것은 첫 번째 버전이 트랜잭션 2699와 함께 작동하고 2700에서 새 버전으로 성공적으로 대체
되었다는 것입니다. 그런 다음 2700 이후에 존재했던 다음 버전 UPDATE
은 2702에서 롤백 시도를 보았습니다. HEAP_XMAX_INVALID
.
에 표시된 것처럼 마지막 것은 실제로 태어나지 않았습니다 HEAP_XMIN_INVALID
.
따라서 위의 추측에서 첫 번째와 마지막 경우는 분명합니다. 트랜잭션 2703 이상에서는 더 이상 볼 수 없습니다.
두 번째는 어딘가에서 조회해야합니다. 커밋 로그 일명이라고 생각합니다 clog
.
문제를 더 복잡하게하기 UPDATE
위해 다음과 같은 결과가 나타납니다.
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
여기에 이미 보이는 두 후보가 있습니다. 마지막으로 여기 내 질문이 있습니다.
clog
이 경우 가시성을 결정하기 위해 볼 곳이 있다고 가정 합니까?- 시스템에
clog
? 를 방문하도록 지시하는 플래그 (또는 플래그 조합)는 무엇입니까? - 안에 무엇이 있는지 검사하는 방법이
clog
있습니까?clog
이전 버전의 Postgres 손상에 대한 언급 과 가짜 파일을 수동으로 만들 수 있다는 힌트가 있습니다. 이 정보는 많은 도움이 될 것입니다.