Postgresql

是什麼導致了大的單個索引大小(除了膨脹?)

  • November 28, 2019

我一直在深入研究我們生產的 PostgreSQL 9.6 數據庫的大小,發現一些我認為令人驚訝的結果。

foos我們有一個包含大約1000 萬條記錄的表(我們稱之為) 。主鍵是一個integer. 我們在這張表上有一個 B 樹索引,用於將可選外鍵插入另一個表(我們稱之為bars)。我們稱之為索引index_foos_on_bar_idbars.id只是一個integer數據類型列。

當我使用 meta 命令查看索引大小時,\di+我發現它佔用了大約1GB的空間。一些粗略的數學運算意味著索引中的每個條目因此每行佔用大約 1GB / 1000 萬 = 100 字節的空間

表上幾乎沒有刪除foos,因此不存在膨脹。

在我看來,索引將有效地包含諸如將索引列映射到相關表的主鍵的排序數字對之類的東西。但是,由於它只是integer類型,因此每行僅使用大約 4 + 4 = 8 個字節,這與實際佔用的每行 100 個字節相差甚遠。我想它是一個樹形結構的事實可能會稍微提高一點,但超過 10 倍的差異對我來說有點令人側目。

是什麼解釋了索引使用的所有這些“額外”空間?

foos 表上幾乎沒有刪除,因此不存在膨脹。

您不需要刪除即可獲得膨脹。更新也會這樣做。一個新創建的 10,000,000 個整數的索引給了我 214MB 的大小,所以你確實有膨脹(或者正在使用奇怪的硬體,也許)。你不能僅僅通過思考來檢測膨脹。重建索引並查看它是否變小,或使用pgstattuple。當然,擁有一個緊湊的索引並不是很有效,因為幾乎每個操作都需要進行頁面拆分。

您對索引的心理模型與 PostgreSQL 的處理方式不匹配。

索引不指向主鍵值,它直接指向表。這稱為“tid”,通常佔用 6 個字節。

數據值本身儲存為 8 字節對齊,所以即使你的數據是 int4,它仍然需要 8 字節的磁碟空間。由於這種對齊方式,您可以在兩個 int4 列上建構索引,並且它仍將採用與一個 int4 列相同的大小。

PostgreSQL 總是準備好處理每一行的 NULL 值以及可變長度數據,即使表/索引的定義排除了這些事情。所以每個索引元組都有一個標題,它告訴我們該行是否有任何 NULL 或可變長度數據,以及該元組的總長度。這會佔用一些空間。

PostgreSQL 使用頁面組織儲存,而不僅僅是一個巨大的 malloc 塊。每個頁面都包含更多的成本,包括每個塊和塊內的每個條目(請參閱 typedef struct ItemIdData)。

因此,您將獲得 8 個字節用於數據本身(bar_id,aligned)、8 個字節的元組標頭(包括 tid 指針)和 4 個字節用於每個塊內的行指針,最多 20 個字節。由於非葉頁面的一些成本加上每個塊的成本以及塊內的一些空間由於對齊或因為它們位於數據的參差不齊的末端而無法使用,我得到的實際值為 22.4 字節。其他 4.5 倍將是膨脹(儘管一些“膨脹”可能是有用的可用空間,除非您的索引從現在開始將是絕對靜態的)

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