การมองเห็นแถวถูกกำหนดอย่างไร?


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

ตามโมเดลMVCC ที่ใช้ PostgreSQL จะมีการเขียนฟิสิคัลแถวใหม่และอันเก่าไม่ถูกต้อง (สามารถเห็นได้จาก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ถูกตั้งค่าเป็นบางอย่าง อย่างไรก็ตามสิ่งนี้ธุรกรรมที่ตามมาสามารถเห็นแถวนี้ (ไม่เปลี่ยนแปลง)

หลังจากที่ได้อ่านเกี่ยวกับเรื่องนี้แล้วคุณอาจจะเข้าใจถึงการมองเห็นของแถว มีแผนที่การมองเห็นแต่จะบอกได้เฉพาะเมื่อมองเห็นทั้งหน้า - แน่นอนว่ามันไม่สามารถใช้งานได้ในระดับแถว (tuple) แล้วมีบันทึกการกระทำ (aka clog) - แต่ Postgres จะหาวิธีได้อย่างไรหากต้องเข้าชม

ฉันตัดสินใจที่จะดูบิตของ infomaskเพื่อดูว่าการมองเห็นใช้งานได้จริงอย่างไร จะเห็นพวกเขาวิธีที่ง่ายที่สุดคือการใช้ส่วนขยาย pageinspect เพื่อค้นหาว่าบิตใดถูกตั้งค่าฉันได้สร้างตารางเพื่อจัดเก็บ:

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 หรือสูงกว่าได้อีกต่อไป อันที่สองต้องถูกมองหาที่ไหนสักแห่ง - ฉันคิดว่ามันเป็นบันทึกการกระทำหรือที่เรียกว่าอุดตัน

2 HEAP_XMAX_INVALIDคนมี นั่นหมายความว่ามันไม่จำเป็นต้องปรึกษาการอุดตันเพราะมีคนทำไปแล้วเห็นว่าสิ่งxmaxนั้นถูกยกเลิกและตั้ง "บิตคำใบ้" เพื่อให้กระบวนการในอนาคตไม่จำเป็นต้องไปที่การอุดตันอีกครั้งสำหรับแถวนั้น

ธงใด (หรือการรวมกันของธง) บอกให้ระบบเยี่ยมชมการอุดตัน?

หากไม่มีheap_xmin_committedหรือheap_xmin_invalidคุณต้องไปที่การอุดตันเพื่อดูว่าการจัดการของ xmin คืออะไร หากธุรกรรมยังอยู่ระหว่างดำเนินการคุณจะไม่เห็นแถวนั้นและคุณไม่สามารถตั้งค่าสถานะใด ๆ ได้ หากการทำรายการกระทำหรือย้อนกลับคุณตั้งค่าheap_xmin_committedหรือheap_xmin_invalidตาม (ถ้าสะดวกในการทำเช่นนั้น - ไม่ใช่ข้อบังคับ) ดังนั้นผู้คนในอนาคตไม่จำเป็นต้องค้นหา

หากxminถูกต้องและมุ่งมั่นและถ้าxmaxไม่เป็นศูนย์และไม่มีheap_max_committedหรือheap_max_invalidจากนั้นคุณต้องไปที่การอุดตันเพื่อดูว่าการจัดการของธุรกรรมนั้นคืออะไร

มีวิธีการตรวจสอบสิ่งที่อยู่ในอุดตันหรือไม่ มีการกล่าวถึงความเสียหายที่เกิดการอุดตันใน Postgres รุ่นก่อนหน้าและมีคำใบ้ว่าสามารถสร้างไฟล์ปลอมด้วยตนเองได้ ข้อมูลชิ้นนี้จะช่วยได้มาก

ฉันไม่ได้ตระหนักถึงวิธีที่ใช้งานง่ายในการทำเช่นนั้น คุณสามารถใช้ "od" เพื่อถ่ายโอนไฟล์ clog ในวิธีที่เหมาะสมในการตรวจสอบและหาตำแหน่งที่จะตรวจสอบโดยใช้มาโครที่กำหนดไว้ในsrc/backend/access/transam/clog.c

ฉันประหลาดใจที่ไม่มีส่วนขยายของ PGXN ที่ทำงานให้คุณได้ แต่ฉันหาไม่เจอ แต่ฉันคิดว่ามันจะไม่เป็นประโยชน์อย่างนั้นเลยเพราะคุณจำเป็นต้องทำสิ่งนี้ในขณะที่เซิร์ฟเวอร์ของคุณไม่ทำงาน


4

มีลักษณะที่HeapTupleSatisfiesMVCC ()การดำเนินงาน: จริงclogการตรวจสอบที่เกิดขึ้นในTransactionIdDidCommit ()แต่มันจะเรียกว่าเฉพาะในกรณีที่สถานะการทำธุรกรรมไม่สามารถอนุมานจากบิต infomask นี้ ( HeapTupleHeaderXminCommitted () แมโคร และเพื่อน ๆ )

ผมเคยย้อนกลับไปที่การเข้าถึงpg_clogฟังก์ชั่นTransactionDidCommit()และแล้วฉันได้มองขึ้นไปที่เหล่านี้จะถูกเรียกว่าเป็นสถานที่เดียวในรหัสที่เกี่ยวข้องกับคำถามของคุณจะปรากฏที่จะอยู่ในTransactionDidAbort() HeapTupleSatisfiesMVCC()จากรหัสของฟังก์ชั่นนี้คุณจะเห็นว่าการค้นหาการอุดตันที่เกิดขึ้นจริงสามารถเกิดขึ้นได้หาก tuple ไม่มีชุด infomask บิตที่เกี่ยวข้อง: รหัสเริ่มต้นด้วยการตรวจสอบบิตด้วยHeapTupleHeaderXminCommitted()et al และการค้นหาการอุดตันจะเกิดขึ้นเฉพาะเมื่อไม่ได้ตั้งค่าบิต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.