web-dev-qa-db-ja.com

インデックス:ノード数が同じ場合の整数と文字列のパフォーマンス

Ruby on Rails with PostgreSQL(9.4)database)でアプリケーションを開発しています。私の使用例では、テーブルの列が非常に頻繁に検索されますが、アプリケーションの全体のポイントは、モデルの非常に特定の属性を検索するためです。

私は現在、列にinteger型を使用するか、通常の文字列型(例:character varying(255)Railsのデフォルト )を使用するかを決定しています、インデックスでのパフォーマンスの違いがどうなるかはわかりません。

これらの列は列挙型です。それらはそれらが持つことができる可能な値の量のための固定サイズを持っています。ほとんどの列挙型の長さは5を超えませんアプリケーションの存続期間を通じてインデックスはほぼ固定されます;したがって、整数インデックスと文字列インデックスはノード数が同じになります。

ただし、インデックスが作成される文字列の長さは約20文字になる可能性があり、メモリ内では整数の約5倍です(整数が4バイトで、文字列が純粋な場合ASCII at 1文字ごとのバイト、これは保持されます。データベースエンジンがインデックスルックアップをどのように実行するかはわかりませんが、一致するまで文字列を「スキャン」する必要がある場合は、正確に、つまり本質的には文字列の検索は整数の検索よりも5倍遅くなります。整数の検索の一致までの「スキャン」は、20ではなく4バイトになります。これは私が想像していることです。

ルックアップ値は(整数)4:

スキャン............................ FOUND |レコードを取得しています... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... |

ルックアップ値は(文字列) "some_val"(8バイト):

走査................................................. .................................... FOUND |レコードを取得しています... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... |

それが理にかなっているといいのですが。基本的に、整数は占有するスペースが少ないため、対応する文字列よりも速く「一致」させることができます。多分これは完全に間違った推測ですが、私は専門家ではないので、私は皆さんにお願いしています! 私が見つけたばかりのこの答え が私の仮説をサポートしているように思われますが、確かにしたいと思います。

列の可能な値の数はどちらを使用しても変化しないため、インデックス自体は変化しません(列挙型に新しい値を追加しない限り)。 この場合、integerまたはvarchar(255)を使用するとパフォーマンスに違いがありますか、または整数型を使用する方が理にかなっていますか?


私が尋ねる理由は、Railsのenum型が整数を文字列キーにマップすることですが、それらはユーザー向けの列を意図していません。検証が実行される前に無効な値がArgumentErrorを引き起こすため、基本的に、列挙値が有効な値であることの検証を行うことはできません。 stringタイプを使用すると検証が可能になりますが、パフォーマンスコストがある場合は、検証の問題を回避するだけで済みます。

27
Chris Cirefice

短い答え:integerは、あらゆる面でvarcharまたはtextより高速です。小さなテーブルや短いキーはそれほど重要ではありません。キーの長さと行数が増えると、その差は大きくなります。

文字列... 20文字長、メモリ内では整数の約5倍です(整数が4バイトで、文字列が純粋な場合ASCII文字あたり1バイト)、これは保持されます)

正確には、文字タイプ(textまたはvarchar)は、20の場合は正確に21バイトを占有しますASCIIディスク上の文字および2 RAM内のバイト数)。詳細な評価:

また重要:COLLATIONルールは、数値データ型とは異なり、文字データのソートをより高価にする可能性があります。

インデックスsizeは、ほとんどの場合、パフォーマンスの違いの大きな部分を占めています。インデックスタプルごとにoverheadを検討してください(基本的にはテーブルの場合と同じです):4バイトアイテムポインターおよび24バイトタプルヘッダー。したがって、integerのインデックスタプルは6バイト(4バイトのalignment paddingを含む)およびvarchar(20) for 20 ASCII文字52バイト(パディングも含む)詳細:

すべての理論は別として、単にテストするのが最善です。

Postgres 9.5は、文字データの長い文字列をソートするための最適化を導入しました(key Word "abbreviated keys")。しかし、Linuxの一部のCライブラリ関数のバグにより、プロジェクトはPostgres 9.5.2の非C照合の機能を無効にする必要がありました。 リリースノートの詳細

ただし、実際にPostgres enum型を使用する場合、これらの考慮事項のほとんどは、内部的にinteger値を使用して実装されているため、無関係です。 マニュアル:

enum値は、ディスク上で4バイトを占有します。

補足:varchar(255)は、SQL Serverの初期のバージョンでは意味がありましたが、255文字までの内部でより効率的なデータ型を使用できました。ただし、255文字の奇数の長さ制限は、Postgresのパフォーマンスにまったく影響を与えません。

33