PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL Upsert разграничава вмъкнатите и актуализираните редове с помощта на системни колони XMIN, XMAX и други

Мисля, че това е интересен въпрос, който заслужава задълбочен отговор; моля, потърпете, ако е малко продължително.

Накратко:Вашето предположение е правилно и можете да използвате следния RETURNING клауза, за да се определи дали редът е бил вмъкнат и не е актуализиран:

RETURNING (xmax = 0) AS inserted

Сега подробното обяснение:

Когато един ред се актуализира, PostgreSQL не променя данните, а създава нова версия на реда; старата версия ще бъде изтрита чрез autovacuum когато вече не е необходимо. Версия на ред се нарича кортежка , така че в PostgreSQL може да има повече от един кортеж на ред.

xmax служи за две различни цели:

  1. Както е посочено в документацията, това може да бъде идентификаторът на транзакцията на транзакцията, която е изтрила (или актуализира) кортежа („кортежа“ е друга дума за „ред“). Само транзакции с идентификатор на транзакция между xmin и xmax може да види кортежа. Стар кортеж може да бъде изтрит безопасно, ако няма транзакция с идентификатор на транзакция по-малък от xmax .

  2. xmax се използва също за съхраняване на ключалки на редове . В PostgreSQL заключванията на редове не се съхраняват в таблицата за заключване, а в кортежа, за да се избегне препълване на таблицата за заключване.
    Ако само една транзакция има заключване на реда, xmax ще съдържа идентификатора на транзакцията на заключващата транзакция. Ако повече от една транзакция има заключване на реда, xmax съдържа номера на така наречения мултиакт , което е структура от данни, която от своя страна съдържа идентификаторите на транзакциите на заключващите транзакции.

Документацията на xmax не е пълно, тъй като точното значение на това поле се счита за детайл от изпълнението и не може да бъде разбрано без да се знае t_infomask на кортежа, който не се вижда веднага чрез SQL.

Можете да инсталирате модула contrib pageinspect за да видите това и други полета на кортеж.

Пуснах вашия пример и това виждам, когато използвам heap_page_items функция за проверка на подробностите (разбира се, идентификационните номера на транзакциите са различни в моя случай):

SELECT *, ctid, xmin, xmax FROM t;

┌───┬────┬───────┬────────┬────────┐
│ i │ x  │ ctid  │  xmin  │  xmax  │
├───┼────┼───────┼────────┼────────┤
│ 1 │ 11 │ (0,2) │ 102508 │ 102508 │
│ 2 │ 22 │ (0,3) │ 102508 │      0 │
└───┴────┴───────┴────────┴────────┘
(2 rows)

SELECT lp, lp_off, t_xmin, t_xmax, t_ctid,
       to_hex(t_infomask) AS t_infomask, to_hex(t_infomask2) AS t_infomask2
FROM heap_page_items(get_raw_page('laurenz.t', 0));

┌────┬────────┬────────┬────────┬────────┬────────────┬─────────────┐
│ lp │ lp_off │ t_xmin │ t_xmax │ t_ctid │ t_infomask │ t_infomask2 │
├────┼────────┼────────┼────────┼────────┼────────────┼─────────────┤
│  1 │   8160 │ 102507 │ 102508 │ (0,2)  │ 500        │ 4002        │
│  2 │   8128 │ 102508 │ 102508 │ (0,2)  │ 2190       │ 8002        │
│  3 │   8096 │ 102508 │      0 │ (0,3)  │ 900        │ 2           │
└────┴────────┴────────┴────────┴────────┴────────────┴─────────────┘
(3 rows)

Значенията на t_infomask и t_infomask2 може да се намери в src/include/access/htup_details.h . lp_off е отместването на кортежните данни в страницата и t_ctid е текущият идентификатор на кортежа който се състои от номера на страницата и номер на кортежа в страницата. Тъй като таблицата е новосъздадена, всички данни са на страница 0.

Позволете ми да обсъдя трите реда, върнати от heap_page_items .

  1. В указател на линия (lp ) 1 намираме стария, актуализиран кортеж. Първоначално имаше ctid = (0,1) , но това беше променено, за да съдържа идентификатора на кортежа на текущата версия по време на актуализацията. Кортежът е създаден от транзакция 102507 и невалиден от транзакция 102508 (транзакцията, която е издала INSERT ... ON CONFLICT ). Този кортеж вече не се вижда и ще бъде премахнат по време на VACUUM .

    t_infomask показва, че и двете xmin и xmax принадлежат към извършени транзакции и следователно показват кога кортежите са създадени и изтрити. t_infomask2 показва, че кортежът е актуализиран с HOT (кортеж само за heap ) update, което означава, че актуализираният кортеж е на същата страница като оригиналния кортеж и нито една индексирана колона не е променена (вижте src/backend/access/heap/README.HOT ).

  2. В указател на ред 2 виждаме новия, актуализиран кортеж, който е създаден чрез транзакция INSERT ... ON CONFLICT (транзакция 102508).

    t_infomask показва, че този кортеж е резултат от актуализация, xmin е валиден и xmax съдържа KEY SHARE заключване на редове (което вече не е от значение, след като транзакцията е приключила). Това заключване на ред е взето по време на INSERT ... ON CONFLICT обработка. t_infomask2 показва, че това е HOT кортеж.

  3. При указател на ред 3 виждаме нововмъкнатия ред.

    t_infomask показва, че xmin е валиден и xmax е невалидно. xmax е зададено на 0, защото тази стойност винаги се използва за нововмъкнати кортежи.

Така че ненулевият xmax на актуализирания ред е артефакт на реализацията, причинен от заключване на ред. Възможно е INSERT ... ON CONFLICT се прилага отново един ден, така че това поведение да се промени, но мисля, че това е малко вероятно.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. За предимствата на сортираните пътища

  2. Мигриране от DB2 към PostgreSQL – какво трябва да знаете

  3. Как да броим дните с изключение на неделята между две дати в Postgres?

  4. Интервал за съвпадение на PostgreSQL между началния и крайния час спрямо времевата марка

  5. Инсталиране на PostgreSQL Extension към всички схеми