INSERTS
Postgres でデータベース インデックスを作成するコスト (遅い、インデックスを作成する時間、インデックスを再作成する時間) がパフォーマンスの向上 (速い) に見合うかどうかを判断するための良い方法はありますSELECTS
か?
3 に答える
私は実際に Hexist に反対するつもりです。PostgreSQL のプランナーは非常に優れており、物理順序スキャンに基づくテーブル ファイルへの適切なシーケンシャル アクセスをサポートしているため、インデックスが必ずしも役立つとは限りません。さらに、プランナーがインデックスを選択しなければならない場合も多くあります。さらに、一意の制約と主キーの主キーを既に作成しています。
PostgreSQL (MySQL はまったく別のものです!) での適切なデフォルトの位置の 1 つは、インデックスを追加する必要があるまで待ってから、最も明確に必要なインデックスのみを追加することだと思います。ただし、これは単なる出発点であり、クエリ プランを確認する一般的な経験がないか、アプリケーションがどこに向かう可能性があるかを理解していないことを前提としています。これらの分野での経験は重要です。
一般に、テーブルが 10 ページ (40kb のデータとヘッダー) を超える可能性がある場合は、外部キーを使用することをお勧めします。これらは明らかに必要であると考えられます。1 ページにまたがる小さなルックアップ テーブルは、非一意のインデックスを持つべきではありません。これは、これらのインデックスが選択に使用されることはないためです (単一ページのシーケンシャル スキャンに勝るクエリ プランはありません)。
その点を超えて、データの分布についても検討する必要があります。通常、ブール型の列にインデックスを作成することはお勧めできません。ブール型の検索に関連するものにインデックスを付けるには、より良い方法があります (部分インデックスが良い例です)。同様に、一般的に使用される関数の出力にインデックスを付けることは、良いアイデアのように思える場合もありますが、常にそうであるとは限りません。検討:
CREATE INDEX gj_transdate_year_idx ON general_journal (extract('YEAR' FROM transdate));
これはあまり役に立ちません。ただし、transdate のインデックスは、再帰 CTE を介したスパース インデックス スキャンと組み合わせると便利な場合があります。
基本的なインデックスを配置したら、他にどのようなインデックスを追加する必要があるかが問題になります。これは、多くの場合、最初に設計されたものよりも後のユース ケース レビューに任せたほうがよいでしょう。PostgreSQL のインデックス数を減らすことでパフォーマンスが大幅に向上することは珍しくありません。
考慮すべきもう 1 つの重要な点は、作成するインデックスの種類であり、これらは多くの場合、ユースケース固有のものです。たとえば、配列レコードの b ツリー インデックスは、順序がドメインにとって重要であり、初期要素に基づいて頻繁に検索する場合に意味があるかもしれませんが、順序が重要でない場合は、GIN インデックスをお勧めします。ほとんど役に立ちません (もちろん、これはアトミック性に関する危険信号ですが、Pg では意味がある場合もあります)。順序性が重要な場合でも、順序性が重要ではないかのように交換スキャンを実行できるようにする必要があるため、とにかく GIN インデックスが必要になることがあります。これは、たとえば ip4r を使用して cidr ブロックを格納し、EXCLUDE 制約を使用してブロックに他のブロックが含まれないようにする場合に当てはまります (実際のスキャンでは、包含演算子ではなくオーバーラップ演算子を使用する必要があります。
繰り返しますが、これはややデータベース固有です。たとえば、MySQL では、Hexist の推奨事項は正しいでしょう。ただし、PostgreSQL では、問題を監視することをお勧めします。
測定に関する限り、最良のツールはEXPLAIN ANALYZE
一般的に言って、selectを頻繁に実行しないログまたはアーカイブテーブルがない限り(または実行に時間がかかる場合は問題ありません)、select / update/deeleteステートメントがwhereで使用するものすべてにインデックスを付ける必要があります。句。
ただし、これは必ずしも見た目ほど単純ではありません。列がwhere句で使用され、インデックスが付けられているからといって、SQLエンジンがインデックスを使用できるとは限りません。EXPLAIN
postgresqlのand機能を使用するとEXPLAIN ANALYZE
、selectで使用されたインデックスを調べて、列にインデックスを付けることが役立つかどうかを判断するのに役立ちます。
これは一般的に当てはまります。インデックスがないと、選択速度はO(log n)ルック操作からO(n)まで低下しますが、挿入速度はcO(log n)からdO(log n)までしか向上しません。ここでdは通常はc未満です。つまり、インデックスを作成しないことで挿入を少し高速化できますが、インデックスが作成されていない場合は選択した速度を停止するため、データにインデックスを作成することはほとんどの場合価値があります。あなたがそれに対して選択するつもりなら。
さて、たくさんの挿入と更新を行い、すべてのエントリを頻繁に削除し、定期的にいくつかの選択を行うだけの小さなテーブルがある場合、インデックスがない方が速いことがわかります。かなり特殊なケースのシナリオであるため、ベンチマークを実行して、特定のケースでそれが理にかなっているかどうかを判断する必要があります。
良い質問です。@hexist がすでに言及したことと、@ypercube のリンクによって提供される情報にもう少し追加したいと思います。
設計上、データベースは、提供された述語を満たすデータをテーブルのどの部分で見つけるかを知りません。したがって、DB はすべてのテーブルのデータのフル スキャンまたはシーケンシャル スキャンを実行し、必要な行をフィルタリングします。
インデックスは特別なデータ構造であり、特定のテーブルのどの行でそのような値が見つかるkey
かを正確に指定できます。インデックスが関係する場合の主な違い:
- インデックス スキャン自体にコストがかかります。つまり、DB は最初にインデックス内の値を見つける必要があります。
- テーブル自体から特定のデータを読み取るには追加のコストがかかります。
インデックスを操作すると、フル スキャンで使用されるシーケンシャル IO パターンと比較して、ランダム IO パターンになります。ランダム ディスク アクセスとシーケンシャル ディスク アクセスの比較数値をグーグルで検索できますが、最大で 1 桁異なる場合があります (もちろん、ランダムは低速です)。
それでも、インデックス アクセスの方が安価な場合もあれば、フル スキャンが優先される場合もあることは明らかです。これは、指定された述語によって返される (すべての) 行の数、またはその選択性によって異なります。
- 述語が比較的少数の行を返す場合、たとえば、全体の 10% 未満の行を返す場合は、Index を介して直接それらを選択する価値があるようです。これは、主/一意のキーまたは次のようなクエリの典型的なケースです
I need address information for customer with internal number = XXX
。 - 述語が選択性に大きな影響を与えない場合、つまり 30% (またはそれ以上) の行が返される場合は、フル スキャンを実行する方が安価です。シーケンシャル ディスク アクセスがランダムに勝って、データがより速く配信されるからです。大きな領域 (月、またはすべての顧客など) をカバーするすべてのレポートがここに分類されます。
- 値の順序付きリストを取得する必要があり、インデックスがある場合は、インデックス スキャンを実行するのが最速のオプションです。これは #2 の特殊なケースで、レポート データを特定の列で並べ替える必要がある場合です。
- 列内の個別の値の数が、値の総数と比較して比較的少ない場合は、インデックスが適切な選択になります。これはLoose Index Scanと呼ばれるケースで、典型的なクエリは次のようになります
I need 20 most recent purchases for each of the top 5 categories by number of goods
。
DB はどのようにインデックスまたはフル スキャンを実行するかを決定しますか? これは実行時の決定であり、統計に基づいているため、それらを最新の状態に保つようにしてください。実際、上記の数値には実際の値はありません。各クエリを個別に評価する必要があります。
これはすべて、何が起こるかを非常に大まかに説明したものです。How PostgreSQL Planner Uses Statisticsを調べることを強くお勧めします。これは、この件に関して私が見た中で最高のものです。