25

構造 {integer, integer, integer, timestamp without time zone} を持つ大きな (1 億行以上) Postgres テーブルを取得しました。行のサイズは 3*integer + 1*timestamp = 3*4 + 1*8 = 20 バイトになると予想していました。

実際の行サイズはpg_relation_size(tbl) / count(*)52 バイトです。なんで?

(テーブルに対して削除は行われません: pg_relation_size(tbl, 'fsm')~= 0)

4

2 に答える 2

54

行サイズの計算は、それよりもはるかに複雑です。

通常、ストレージは 8 kB のデータ ページに分割されます。ページごとに小さな固定オーバーヘッドがあり、残りが別のタプルに収まるほど大きくない可能性があり、さらに重要なことに、デッド行またはFILLFACTOR設定で最初に予約されたパーセンテージがあります。

また、行(タプル)ごとにさらに多くのオーバーヘッドがあります。ページの先頭にある 4 バイトの項目識別子HeapTupleHeader、23 バイトの 、および配置パディングです。タプル ヘッダーの開始とタプル データの開始は、 の倍数 (MAXALIGN一般的な 64 ビット マシンでは 8 バイト) で配置されます。一部のデータ型では、次の 2、4、または 8 バイトの倍数に位置合わせする必要があります。

システムテーブルのマニュアルを引用pg_tpye

typalignこの型の値を格納するときに必要な配置です。これは、ディスク上のストレージだけでなく、PostgreSQL 内の値のほとんどの表現にも適用されます。ディスク上の完全な行の表現など、複数の値が連続して格納される場合、指定された境界で始まるように、このタイプのデータムの前にパディングが挿入されます。位置合わせ参照は、シーケンス内の最初のデータムの始まりです。

可能な値は次のとおりです。

  • c=char整列、つまり、整列は必要ありません。

  • s=short整列 (ほとんどのマシンでは 2 バイト)。

  • i=int整列 (ほとんどのマシンでは 4 バイト)。

  • d=doubleアライメント (多くのマシンでは 8 バイトですが、すべてではありません)。

マニュアルの基本については、こちらをご覧ください。

あなたの例

integerこれにより、3列の後に 4 バイトのパディングが発生します。これは、timestamp列にはdouble位置合わせが必要であり、次の 8 バイトの倍数から開始する必要があるためです。

したがって、1 行が占めます。

   23   -- heaptupleheader
 +  1   -- padding or NULL bitmap
 + 12   -- 3 * integer (no alignment padding here)
 +  4   -- padding after 3rd integer
 +  8   -- timestamp
 +  0   -- no padding since tuple ends at multiple of MAXALIGN

さらに、ページ ヘッダーのタプルごとのアイテム識別子 (コメントで @AH が指摘したように):

 +  4   -- item identifier in page header
------
 = 52 bytes

したがって、観測された52 バイトに到達します。

計算pg_relation_size(tbl) / count(*)は悲観的な見積もりです。pg_relation_size(tbl)膨張 (無駄な行) と によって予約されたスペースfillfactor、およびデータ ページごとおよびテーブルごとのオーバーヘッドが含まれます。(また、 TOAST テーブルvarlenaの長いデータの圧縮については触れていません。ここでは適用されないためです。)

追加のモジュールpgstattupleSELECT * FROM pgstattuple('tbl_name');をインストールして、テーブルとタプルのサイズに関する詳細情報を呼び出すことができます。

関連している:

于 2012-11-26T18:23:42.023 に答える
5

各行にはメタデータが関連付けられています。正しい式は次のとおりです(ナイーブな配置を想定):

3 * 4 + 1 * 8 == your data
24 bytes == row overhead
total size per row: 23 + 20

または約53バイト。私は実際にpostgresql-varintを作成して、この正確なユースケースでこの問題を解決できるようにしました。タプルオーバーヘッドに関する追加の詳細については、同様の投稿を参照することをお勧めします。

于 2012-11-26T18:15:49.603 に答える