作者:胡彬 騰訊雲進階工程師
TOAST 是“ The Oversized-Attribute Storage Technique ”的縮寫,主要用于存儲一個大字段的值。要了解 TOAST ,我們要先了解頁( BLOCK )的概念。在 PG 中,頁是資料在檔案存儲中的基本機關,其大小是固定的且隻能在編譯期指定,之後無法修改,預設的大小為8 KB 。同時,PG 不允許一行資料跨頁存儲,那麼對于超長的行資料,PG 就會啟動 TOAST ,具體就是采用壓縮和切片的方式。如果啟用了切片,實際資料存儲在另一張系統表的多個行中,這張表就叫 TOAST 表,這種存儲方式叫行外存儲。
在深入細節之前,我們要先了解,在 PG 中每個表字段有四種 TOAST 的政策:
PLAIN :避免壓縮和行外存儲。隻有那些不需要 TOAST 政策就能存放的資料類型允許選擇(例如 int 類型),而對于 text 這類要求存儲長度超過頁大小的類型,是不允許采用此政策的
EXTENDED :允許壓縮和行外存儲。一般會先壓縮,如果還是太大,就會行外存儲
EXTERNA :允許行外存儲,但不許壓縮。類似字元串這種會對資料的一部分進行操作的字段,采用此政策可能獲得更高的性能,因為不需要讀取出整行資料再解壓。
MAIN :允許壓縮,但不許行外存儲。不過實際上,為了保證過大資料的存儲,行外存儲在其它方式(例如壓縮)都無法滿足需求的情況下,作為最後手段還是會被啟動。是以了解為:盡量不使用行外存儲更貼切。
現在我們通過實際操作來研究 TOAST 的細節:
首先建立一張 blog 表:
可以看到,interger 預設 TOAST 政策為 plain ,而 text 為 extended 。PG 資料告訴我們,如果表中有字段需要 TOAST ,那麼系統會自動建立一張 TOAST 表負責行外存儲,那麼這張表在哪裡?
通過上訴語句,我們查到 blog 表的 oid 為16441,其對應 TOAST 表的 oid 為16444(關于 oid 和 pg_class 的概念,請參考PG官方文檔),那麼其對應 TOAST 表名則為: pg_toast.pg_toast_16441(注意這裡是 blog 表的 oid ),我們看下其定義:
TOAST 表有3個字段:
chunk_id :用來表示特定 TOAST 值的 OID ,可以了解為具有同樣 chunk_id 值的所有行組成原表(這裡的 blog )的 TOAST 字段的一行資料
chunk_seq :用來表示該行資料在整個資料中的位置
chunk_data :實際存儲的資料。
現在我們來實際驗證下:
可以看到因為 content 隻有10個字元,是以沒有壓縮,也沒有行外存儲。然後我們使用如下 SQL 語句增加 content 的長度,每次增長1倍,同時觀察 content 的長度,看看會發生什麼情況?
反複執行如上過程,直到 pg_toast_16441 表中有資料:
可以看到,直到 content 的長度為327680時(已遠遠超過頁大小 8K),對應 TOAST 表中才有了2行資料,且長度都是略小于2K,這是因為 extended 政策下,先啟用了壓縮,然後才使用行外存儲。
下面我們将 content 的 TOAST 政策改為 EXTERNA ,以禁止壓縮。
然後我們再插入一條資料:
然後重複以上步驟,直到TOAST表中産生新的行:
這次我們看到當 content 長度達到2560(按照官方文檔,應該是超過2KB左右), TOAST 表中産生了新的2條 chunk_id 為16448的行,且2行資料的 chunk_data 的長度之和正好等于2560。通過以上操作得出以下結論:
如果政策允許壓縮,則TOAST優先選擇壓縮。
不管是否壓縮,一旦資料超過2KB左右,就會啟用行外存儲。
修改TOAST政策,不會影響現有資料的存儲方式。
相關推薦
在雲端快速建構一個 ODOO 站點
微信支付商戶系統架構背後的故事