web-dev-qa-db-ja.com

PostgreSQLの「カテゴリ」が多すぎる場合、列挙型を使用しますか?

問題

1,000万レコードを超えるCSVをPostgreSQL v12.1にロードすることを計画しています。その列の1つに「カテゴリ」値があるため、列挙型を作成することは適切な選択のようですが、208のカテゴリを保持しています。

最短フィールドは2、最長フィールドは11文字です。すべてのフィールドの平均は2.4です。文字エンコードはUTF8ですが、 すべての文字はASCII です。

質問:

enumeratedvarcharのどちらを使用すればよいですか?

追加情報

charを破棄します。これは、PostgreSQLの公式ドキュメント statescharvarcharおよびtext

ヒント:これら3つのタイプの間にパフォーマンスの違いはありませんが、空白で埋められたタイプを使用した場合のストレージスペースの増加、および長さ制約のある列に格納するときに長さをチェックするための追加のCPUサイクルがいくつかあります。 character(n)は他のいくつかのデータベースシステムではパフォーマンス上の利点がありますが、PostgreSQLにはそのような利点はありません。実際、追加のストレージコストのため、character(n)は通常3つの中で最も遅いです。ほとんどの場合、代わりにテキストまたは文字の変化を使用する必要があります。

PostgreSQLのenum値は ディスク上の4バイト を占有します(8.7.4。実装の詳細を参照)。これと、enum型を使用した2.4の平均文字列長を考慮すると、ディスク使用量がわずかに高くなります(PostgreSQLの短い文字列には、1バイトの追加ディスク領域が必要です)。それでも私は、列挙型を使用する方がより良い選択であると考えています。その実装により、多くの操作が列挙型に対して高速になるためです。

4
atevm

平均2.4文字(より関連性が高い:平均バイト-しかし、すべてのASCII文字)と同じです)列挙型を使用する必要はありませんこれらは、ディスク上の4バイトと、場合によってはアライメントパディングを占有します(textは、アライメントパディングを必要としません。)ストレージを節約することすらせず、そのためのオーバーヘッドが増えます。

7文字(=ディスク上の8バイト)未満のほとんどの値では、textカテゴリー列のインデックスもenumのインデックスよりもわずかに大きくなります。 (データ用のスペースは、(通常)8バイトの倍数で割り当てられます。)

固定数の208カテゴリの場合、"char"エンコーディング(char!と混同しないでください)は、ストレージを節約するためのオプションです。見る:

しかし、繰り返しになりますが、そのような小さな文字列については問題がありません。 textを使用するだけです。多分 FK制約 を使用してcategoryテーブルに正確さを強制します:

CREATE TABLE category (category text PRIMARY KEY);

また、カテゴリごとに追加情報を保存するのにも適しています。また、カテゴリのセットを簡単に変更できます。 FK制約を作成するON UPDATE CASCADEそして、1つの中心的な場所でカテゴリ名を変更できます。成功する ON DELETE SET NULL、カテゴリを簡単に削除できます。等。

関連:

6

私はアーウィンの答えを完全にサポートしますが、列挙型に対する警告を追加したいと思いました。

列挙型は、変更できない一定の数の可能な値がある場合に適しています(少なくとも、値を削除する必要がないことが保証されている必要があります)。

他のすべてのケースでは、列挙型を使用しないでください:一度追加した列挙値を削除することは不可能です。

たとえば、米国の州を含む列のデータ型を選択するとき、列挙型を選択することはしないです。国家が離脱する、または2つの国家が合体すること。

データの記述方法に基づいて、列挙型はお勧めしません。

2
Laurenz Albe