Postgresql

PostgreSQL Index Only Scan 不能返回 ctid

  • May 2, 2020

我在 PostgreSQL 11 中有這張表:

CREATE TABLE A (id bigint PRIMARY KEY, text text)

現在我想獲取ctid滿足某些條件的行,例如id = 123.

然而,即使pg_hint_plan用來提示 PostgreSQL 使用Index Only Scan,它也總會給我Index Scan

/*+ IndexOnlyScan(a) */ explain analyze select ctid from a where id = 823977776533426178;
                                               QUERY PLAN                                                
----------------------------------------------------------------------------------------------------------
Index Scan using a_pkey on a  (cost=0.14..8.16 rows=1 width=6) (actual time=0.038..0.039 rows=1 loops=1)
  Index Cond: (id = '823977776533426178'::bigint)
Planning Time: 0.122 ms
Execution Time: 0.095 ms
(4 rows)

我的理解是ctid每行的物理行ID(block_no:record_offset),它必須包含在任何btree索引中,因為它需要這些資訊來從堆文件中獲取行。

那麼為什麼僅索引掃描不能ctid直接返回呢?

只是PostgreSQL沒有那樣實現它嗎?

您的理解幾乎但並不完全正確。確實,每個 btree 索引元組都需要一個ctid(或某種形式的塊號和元組索引)來指向堆元組(表行)。但是(至少)自從 Postgres 8.3 引入“僅堆元組”以來,可能有一條HOT 鏈可以跟隨以到達快照中的目前活動元組 - 與儲存在索引中的元組不同。ctid

由於也不可能使用ctid(或任何系統列)作為索引表達式,因此目前(以及在可預見的將來)完全不可能ctid從僅索引掃描中獲得 a 。

有關的:

在 Index-only_scans / Interaction_with_HOT 上引用Postgres Wiki :

借助 HOT,索引掃描可以遍歷所謂的 HOT 鏈;它可以從物理索引元組(可能由原始 INSERT 創建,並且與邏輯元組的早期版本相關)到相應的物理堆元組。堆元組本身將包含指向元組的下一個版本(即元組 ctid)的指針,而後者又可能有自己的指針。索引掃描最終會根據查詢的快照到達目前的元組。

引用自:https://dba.stackexchange.com/questions/234740