행 가시성은 정확히 어떻게 결정됩니까?


10

가장 간단한 경우 테이블에 새 행을 삽입하면 (및 트랜잭션 커밋) 모든 후속 트랜잭션에 표시됩니다. 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 손상에 대한 언급 과 가짜 파일을 수동으로 만들 수 있다는 힌트가 있습니다. 이 정보는 많은 도움이 될 것입니다.

답변:


6

따라서 위의 추측에서 첫 번째와 마지막 경우는 분명합니다. 트랜잭션 2703 이상에서는 더 이상 볼 수 없습니다. 두 번째는 어딘가에서 찾아야합니다. 커밋 로그, 일명 clog라고 가정합니다.

두 번째는 HEAP_XMAX_INVALID. 그것은 누군가가 이미 그렇게했기 때문에 막힘을 상담 할 필요가 없다는 것을 의미합니다. 누군가 xmax가 중단 된 것을 보았고 "힌트 비트"를 설정하여 향후 프로세스가 해당 행에 대해 막힘을 다시 방문 할 필요가 없도록합니다.

어떤 플래그 (또는 플래그의 조합)가 시스템에 막힘을 방문하도록 지시합니까?

heap_xmin_committed또는 이 없으면 heap_xmin_invalidxmin의 처리가 무엇인지 확인하려면 막힘을 방문해야합니다. 트랜잭션이 여전히 진행 중이면 행이 표시되지 않으며 플래그를 설정할 수 없습니다. 트랜잭션이 커밋되거나 롤백 된 경우 미래의 사람들이 조회 할 필요가 없도록 heap_xmin_committed또는 heap_xmin_invalid그에 따라 (그렇게하는 것이 편리하다면 필수가 아닌 경우) 설정합니다.

경우는 xmin유효하고 최선을 다하고 없으며, 경우는 xmax0이 아닌, 거기에는있다 heap_max_committed또는 heap_max_invalid당신은 트랜잭션의 처리가 무엇인지 확인하기 위해 막힘을 방문해야한다.

막힌 내용물을 검사하는 방법이 있습니까? 이전 버전의 Postgres의 막힘에 대한 언급과 가짜 파일을 수동으로 만들 수 있다는 힌트가 있습니다. 이 정보는 많은 도움이 될 것입니다.

사용자 친화적 인 방법을 알지 못합니다. "od"를 사용하여 적절한 방법으로 clog 파일을 덤프하고 파일에 정의 된 매크로를 사용하여 검사 할 위치를 파악할 수 있습니다.src/backend/access/transam/clog.c

PGXN에 당신을 위해 일하는 확장 프로그램이 없다는 것에 놀랐지 만 찾을 수 없었습니다. 그러나 서버가 실행되지 않는 동안 실제로 할 수 있어야하기 때문에 유용하지는 않다고 생각합니다.


4

HeapTupleSatisfiesMVCC () 구현을 살펴보십시오 . 실제 clog확인은 TransactionIdDidCommit () 에서 발생 하지만 정보 마스크 비트 ( HeapTupleHeaderXminCommitted () 매크로 및 친구) 에서 트랜잭션 상태를 유추 할 수없는 경우에만 호출됩니다 .

나는 다시 액세스를 추적 한 pg_clog기능들 TransactionDidCommit()TransactionDidAbort()이러한 호출하고 귀하의 질문에 관련 코드에있는 유일한 장소에있는 것으로 보인다 어디 그럼 내가 고개를했습니다 HeapTupleSatisfiesMVCC(). 이 함수의 코드에서 튜플에 관련 정보 마스크 비트가 설정되어 있지 않은 경우에만 실제 막힘 조회가 발생할 수 있음을 HeapTupleHeaderXminCommitted()알 수 있습니다. 코드는 et al. 막힘 조회는 비트가 설정되지 않은 경우에만 발생합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.