MD5フィールドに最適なデータ型は何ですか?


35

読み取りが多いことがわかっているシステムを設計しています(1分あたり数万回の読み取り)。

  • names一種の中央レジストリとして機能するテーブルがあります。各行には、textフィールドrepresentationkeyそのMD5ハッシュである一意のフィールドがありますrepresentation1現在、このテーブルには数千万のレコードがあり、アプリケーションの存続期間中に数十億に達すると予想されています。
  • テーブルを参照する他の(スキーマとレコード数が非常に異なる)テーブルは多数ありnamesます。これらのテーブルのいずれかのレコードにname_keyは、機能的にはnamesテーブルへの外部キーであるが含まれることが保証されています。

1:ちなみに、ご想像のとおり、このテーブルのレコードは一度書き込まれると不変です。

テーブル以外の特定のnamesテーブルでは、最も一般的なクエリは次のパターンに従います。

SELECT list, of, fields 
FROM table 
WHERE name_key IN (md5a, md5b, md5c...);

読み取りパフォーマンスを最適化したいと思います。私が最初にやるべきことは、インデックスのサイズを最小化することだと思います(ただし、間違っていると証明されてもかまいません)。

質問:
/に最適なデータ型は何ですかれるkeyname_key、列?以上
を使用する理由はありますか?または?hex(32)bit(128)BTREEGIN

回答:


41

データ型uuidはタスク最適です。用RAMに37のバイトとは対照的に、それだけで16バイトを占有varcharまたはtext表現。(またはディスク上で33バイトですが、奇数の場合、多くの場合、効果的に40バイトにするためにパディングが必要になります。)uuidさらに、このタイプにはいくつかの利点があります。

例:

SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash

詳細および詳細説明:

md5の暗号化コンポーネントが不要な場合は、他の(より安価な)ハッシュ関数を検討するかもしれませんが、ユースケース(ほとんど読み取り専用)にはmd5を使用します。

警告の言葉:あなたの場合(immutable once written機能的に依存する(擬似自然)PKは問題ありません。しかし、更新が可能な場合には同じことが苦痛になりますtext。タイプミスを修正することを考えてください:PKおよびすべての依存インデックス、FKカラム、dozens of other tablesおよび他の参照も変更する必要があります。テーブルとインデックスの膨張、ロックの問題、遅い更新、参照の喪失など

text通常の操作で変更できる場合は、代理PKの方が適しています。私は、bigserial列(範囲-9223372036854775808 to +9223372036854775807-それは9五十二十二三十二三十七二十三兆三十六十六何か十億)の異なる値を提案しますbillions of rowsどんな場合でも良いアイデアかもしれません:数十のFKカラムとインデックスに対して16バイトではなく8バイト!)または、はるかに大きなカーディナリティまたは分散システム用のランダムUUID。上記のmd5(as )をいつでも追加保存して、元のテキストからメインテーブル内の行をすばやく見つけることができます。関連:uuid

あなたのクエリに関して


@Danielのコメントに対処するには:ハイフンなしの表現が必要な場合は、表示のためにハイフンを削除します。

SELECT replace('90b7525e-84f6-4850-c2ef-b407fae3f271', '-', '')

しかし、私は気にしません。デフォルトの表現は問題ありません。そして、問題はここの表現ではありません。

他の関係者が異なるアプローチを持ち、ハイフンなしの文字列をミックスにスローする必要がある場合、それも問題ではありません。Postgresは、の入力としていくつかの妥当なテキスト表現を受け入れますuuidドキュメント

PostgreSQLは、入力に次の代替形式も受け入れます。大文字の数字の使用、中括弧で囲まれた標準形式、一部またはすべてのハイフンの省略、4桁のグループの後にハイフンの追加。例は次のとおりです。

A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
a0eebc999c0b4ef8bb6d6bb9bd380a11
a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}

さらに、 md5()関数が戻るとtext、あなたが使用するdecode()に変換byteaし、デフォルトの表現、それは次のとおりです。

SELECT decode(md5('Store hash for long string, maybe for index?'), 'hex')

\220\267R^\204\366HP\302\357\264\007\372\343\362q

encode()元のテキスト表現を取得するには、もう一度する必要があります。

SELECT encode(my_md5_as_bytea, 'hex');

さらに、内部オーバーヘッドのために、byteaRAMに20バイト(およびディスクに17バイト、パディング24バイト)を占有するように格納されている値は、単純なインデックスのサイズとパフォーマンスに特に好ましくありません。varlena

すべてuuidここに有利に働きます。


1
これは「uuid」の合法ですか?面倒すぎるとすみませんが、私が見ているのは、「uuid」データ型は、16オクテットの長さの数値をバイナリ形式で格納することです。ただし、「uuid」という用語は、特定の生成/ハッシュアルゴリズムと、ダッシュで区切られた16進文字の5ブロックでの従来のテキスト表現を示しています。この型名がUUID / GUID生成を強く示唆している場合、少なくともプログラマーにとって、ハッシュを格納するためにこの型を使用することは少し誤解を招かないでしょうか?
アンドリューウルフ

2
@AndrewWolfe:完全に合法です、IMO。運び去られてはいけない名前。これは、便利な一連の型キャストと入出力ロジックを備えた16バイトのエンティティです。手元のケースには、実際には「一意の識別子」が必要です。すべての種類の文字データをtext列に保存することもできます-それが「テキスト」ではない場合でも。
アーウィンブランドステッター16年

MD5ハッシュがbase 64に変換された場合、どのように保存しますか
PirateApp

2
@PirateApp、最初にデコードしますSELECT encode(decode('tZmffOd5Tbh8yXaVlZfRJQ==', 'base64'), 'hex')::uuid;
nyov

1
@nyov:uuid160バイトから512ビットの間で生成されるSHAアルゴリズムの結果を保存できない16バイトのタイプです。Postgresの標準配布に適合する類似のタイプはありません。あなたはそれを作成することができます...それに失敗すると、デフォルトは-pg_cryptoのbyteaように。
アーウィンブランドステッター

2

私はMD5を text or varchar列にます。さまざまな文字データ型の間にパフォーマンスの違いはありません。varchar(xxx)md5値が特定の長さを超えないようにするために使用して、md5値の長さを制限することができます。

通常、大きなINリストは実際には高速ではありません。次のようにすることをお勧めします。

with md5vals (md5) as (
  values ('one'), ('two'), ('three')
)
select t.*
from the_table t
  join md5vals m on t.name_key  = m.md5;

より高速と言われることもある別のオプションは、配列を使用することです。

select t.*
from the_table t
where name_key = ANY (array['one', 'two', 'three']);

同等かどうかを比較しているだけなので、通常のBTreeインデックスで十分です。両方のクエリでこのようなインデックスを使用できる必要があります(特に、行のごく一部しか選択していない場合)。


bit(128)またはhex(32)を使用しない特別な理由はありますか?値はそのようなフィールドにきちんと収まることが保証されており、不適切な値が割り当てられるのを防ぎたいと思います。
-bobocopy

3
@bobocopy:Postgresには「hex」データ型はありません。私はbitタイプを使用したことがないので、コメントすることはできません。行の予想数を考えると、UUID
a_horse_with_no_name

-1

別のオプションは、4つのINTEGER列または2つのBIGINT列を使用することです。


2
もちろん、ストレージのサイズに関しては、どちらのオプションも適合しますが、使用するのはどれほど便利でしょうか?おそらく、答えを展開して例を示したり、それを説明したりできます。
アンドリーM
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.