web-dev-qa-db-ja.com

varchar(n)のオーバーヘッドは何ですか?

varchar(n)タイプに関して Postgres doc からこのフラグメントの意味を尋ねたかったのです。

短い文字列(最大126バイト)のストレージ要件は、1バイトに実際の文字列を加えたもので、文字の場合はスペースのパディングが含まれます。長い文字列は、1ではなく4バイトのオーバーヘッドを持ちます。

varchar(255)フィールドがあるとします。そして今、次のステートメント:

  • このフィールドに10バイトの文字列が含まれている場合、オーバーヘッドは1バイトです。したがって、文字列は11バイトを使用します。
  • フィールドに140バイトの文字列が含まれている場合、オーバーヘッドは4バイトです。したがって、文字列は144バイトを使用します。

上記の説明は正しいですか? ここ 誰かが私と同じようにドキュメントを理解していますが、ここでは誰かがオーバーヘッドは常に4バイトであると述べています ここ

15
keypress

当然のことながら、マニュアルは正しいです。しかし、それだけではありません。

1つは、サイズ on disk table 内、実際にディスクに保存されていない場合でも)は、サイズとは異なります in memory 。ディスクでは、マニュアルに記載されているように、126バイトまでの短いvarchar値のオーバーヘッドは1バイトに削減されます。ただし、オーバーヘッドメモリ内は常に4バイト(個々の値が抽出されると)。

同じことが textvarcharvarchar(n)またはchar(n) にも当てはまります-char(n)n文字まで空白で埋められており、通常は使用しません。 nはバイト数ではなく最大文字数を示すため、マルチバイトエンコーディングでもその有効サイズは変わる可能性があります。

n文字(バイトではない)までの文字列。

それらはすべて内部でvarlenaを使用します。
_"char"_(二重引用符付き)は別の生き物であり、常に1バイトを占有します。
型なし文字列リテラル (_'foo'_)には、1バイトのオーバーヘッドがあります。タイプされた値と混同しないでください!

pg_column_size() でテストします。

_CREATE TEMP TABLE t (id int, v_small varchar, v_big varchar);
INSERT INTO t VALUES (1, 'foo', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');

SELECT pg_column_size(id)        AS id
     , pg_column_size(v_small)   AS v_small
     , pg_column_size(v_big)     AS v_big
     , pg_column_size(t)         AS t
FROM   t
UNION ALL  -- 2nd row measuring values in RAM
SELECT pg_column_size(1)
     , pg_column_size('foo'::varchar)
     , pg_column_size('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar)
     , pg_column_size(ROW(1, 'foo'::varchar, '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar));

 id | v_small | v_big |  t
----+---------+-------+-----
  4 |       4 |   144 | 176
  4 |       7 |   144 | 176
_

ご覧のように:

  • 3バイト文字列 'foo'は、ディスク上で4バイトを占有し、7バイトでRAM(したがって、1バイトと4バイトのオーバーヘッド)。
  • 140バイトの文字列「123 ...」は、ディスクとRAMの両方で144バイトを占有します(したがって、常に4バイトのオーバーヘッド)。
  • integerのストレージにはオーバーヘッドがありません(ただし、パディングを課す可能性があるアライメント要件があります)。
  • 行には、タプルヘッダー用に24バイトの追加オーバーヘッドがあります(ページヘッダーのアイテムポインター用にタプルごとに追加の4バイト)。
  • そして最後に重要なことですが、行のサイズからわかるように、小さいvarcharのオーバーヘッドは、行から抽出されていない間も1バイトです。 (そのため、行全体を選択する方が少し速い場合があります。)

関連:

19