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


26

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

私は現在、使用するかどうかを決定していますintegerタイプを、または単に(例えば、一般的な文字列型を使用character varying(255)Railsのではデフォルトである私は、性能差がインデックスにどうなるかわからないよう、列に対して)。

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

ただし、インデックス付けされる文字列の長さは約20文字で、メモリ内では整数の約5倍になります(整数が4バイトで、文字列が1文字あたり1バイトの純粋なASCIIの場合、これは成り立ちます)。私は、データベースエンジンがインデックスのルックアップを行う方法を知りませんが、それが一致するまで、それは「スキャン」の文字列に必要がある場合は、正確にそして本質的には、手段は、文字列検索が遅くなる整数のルックアップよりも5倍になるということ。整数ルックアップに一致するまでの「スキャン」は20ではなく4バイトになります。これが私が想像していることです。

ルックアップ値は(整数)4です。

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

ルックアップ値は(string) "some_val"(8バイト)です。

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

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

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


私が尋ねる理由は、Railsのenum型は整数を文字列キーにマッピングするが、ユーザー向けの列ではないことです。無効な値はArgumentError検証を実行する前に発生するため、基本的に、列挙値が有効な値であることを確認することはできません。使用stringタイプは、検証が可能になるが、パフォーマンスコストがあります場合、私はむしろちょうど、検証問題を回避ハックと思います。

回答:


32

簡単な答え:あらゆる面でintegervarcharまたはtextあらゆる面で高速です。小さなテーブルや短いキーの場合はそれほど重要ではありません。差はキーの長さと行の数とともに大きくなります。

文字列... 20文字の長さで、メモリ内では整数の約5倍です(整数が4バイトで、文字列が文字ごとに1バイトの純粋なASCIIの場合、これは成り立ちます)

正確には、文字タイプ(textまたはvarchar)は、ディスク上の20個のASCII文字とRAM内の23バイトに対して正確に21バイトを占有します。詳細な評価:

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

ほとんどの場合、インデックスサイズがパフォーマンスの違いを大きく左右します。インデックスタプルごとのオーバーヘッドを考慮してください(基本的にはテーブルの場合と同じです):アイテムポインターに4バイト、タプルヘッダーに24バイト。そうするためのインデックスタプルintegerにあたる36バイト(4つのバイトを含むアライメントパディング)とのためにvarchar(20)、それは次のようになり20 ASCII文字で52バイト(また込みパディング)。詳細:

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

Postgres 9.5は、文字データの長い文字列をソートするための最適化を導入しました(キーワード「略語」)。しかし、Linuxの一部のCライブラリ関数のバグにより、プロジェクトはPostgres 9.5.2の非C照合の機能を無効にしました。リリースノートの詳細。

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

enum値は、ディスク上に4つのバイトを占めています。

余談:varchar(255)SQL Serverの初期バージョンで意味をなすために使用され、255文字の制限まで内部でより効率的なデータ型を使用できました。ただし、255文字という奇妙な長さの制限は、Postgresのパフォーマンスに特別な影響はまったくありません。


1
varchar(255)たとえば、SQL Serverには隠された最適化はありませんvarchar(260)。SQL Server 6.xにはそのようなことがあったかもしれませんが、これは長い間真実ではありませんでした。
a_horse_with_no_name

@a_horse_with_no_name:ありがとう、それに応じて明確にした。
アーウィンブランドステッター

申し訳ありませんが、これを受け入れることをそう長く取るために、私はそのプロジェクトの開発に遅れてきた;)
クリスCirefice

この回答はPostgres 10でも有効ですか?
マティ

1
@Matty:まだ有効です。pg 11でもまだ何も変わっていません。
アーウィンブランドステッター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.