Postgresql
如何確定或預測每個表行的磁碟空間?
我對 Postgres 很陌生,所以我的數學可以在這里關閉…
這是我的桌子:
CREATE TABLE audit ( id BIGSERIAL PRIMARY KEY, content_id VARCHAR (50) NULL, type VARCHAR (100) NOT NULL, size bigint NOT NULL, timestamp1 timestamp NOT NULL DEFAULT NOW(), timestamp2 timestamp NOT NULL DEFAULT NOW() );
我想對 1 行將佔用多少空間進行一些估計。經過一番閱讀,我想出了這個,對嗎?
1 row = 23 (heaptupleheader) + 1 (padding) + 8 (id) + 50 (content_id) + 6 (padding) + 100 (type) + 4 (padding) + 8 (size) + 8 (timestamp) + 8 (timestamp) = 216 bytes
我還在本地 Postgres DB 中創建了同一張表,但數字似乎不匹配:
INSERT INTO public.audit(content_id, type, size) VALUES ('aaa', 'bbb', 100); SELECT pg_size_pretty( pg_total_relation_size('audit') ); -- returns 24 kb INSERT INTO public.audit(content_id, type, size) VALUES ('aaaaaaaaaaaaa', 'bbbbbbbbbbbbbb', 100000000000); SELECT pg_size_pretty( pg_total_relation_size('audit') ); -- still returns 24 kb
這讓我想到 Postgres 保留了 24 kb 的空間,當我輸入更多數據時,一旦超過 24 kb,它會增加 132 個字節?但我內心的某些東西說這不可能。
我想看看 1 行在 Postgres db 中會佔用多少空間,這樣我就可以分析我可以在其中儲存多少數據。也許我錯過了一些非常明顯的東西。
您的計算接近最大裸行大小。實際範圍是每行 68 - 212 個字節,或包括索引在內的 84 - 228 個字節。
最重要的是 a
varchar(n)
不必佔據最大長度。數據類型是用varlena
內部實現的,它為磁碟上的短字元串增加了 1 個字節的成本,加上字元串的實際字節數。實現的數據類型
varlena
不需要在磁碟上進行對齊填充。並且 NULL 值(允許
content_id
)實際上是免費的。看:最後,
PRIMARY KEY
約束是使用標準的 btree 索引實現的。我們必須將其添加到磁碟上的總大小中。所以磁碟上的行大小的計算是:
23 字節元組頭 1 字節填充或空點陣圖 8 字節 id BIGSERIAL PRIMARY KEY 0 - 51 字節 content_id VARCHAR (50) NULL 0 字節對齊填充 2 - 101 字節類型 VARCHAR (100) NOT NULL ? 字節對齊填充 8 字節大小 bigint 非空 8 字節時間戳 1 時間戳 NOT NULL 8 字節時間戳 2 時間戳 NOT NULL --- 最小 64(包括 6 字節填充)- 最大 208 字節(不需要填充) + 堆頁中的 4 字節項目標識符 --- 68 - 212 字節 + 16 個字節用於索引元組 --- 84 - 228 字節
加上這些相關問題中詳述的堆頁面和索引頁面的一些成本:
磁碟上的實際行大小(沒有項目標識符):
SELECT pg_column_size(a) AS size_on_disk, * FROM audit a;
請注意,RAM 中的大小可能不同:
SELECT pg_column_size(content_id) AS content_id_size_on_disk , pg_column_size(content_id || '') AS content_id_size_in_ram , content_id FROM audit a;
看:
關於 …
這讓我想到 Postgres 保留了 24 kb 的空間來啟動
堆以 0 字節開始。索引從一個元頁面 (8kb) 開始。添加第一行後,我們看到第一個堆頁面至少有 8 kb,索引(1 個元頁面 + 第一個索引頁面)至少有 16 kb。細節在小提琴!
db<>在這裡擺弄