私はPostgreSQLテーブルを持っており、それぞれに数百万のレコードと100を超えるフィールドがあります。
そのうちの 1 つは日付フィールドで、これによってクエリでフィルタリングします。この日付フィールドのインデックスを作成すると、小さな範囲の日付を読み取るクエリのパフォーマンスが向上しましたが、大きな範囲の日付ではパフォーマンスが低下しました...
どちらかを優先する必要がありますか?大きな範囲のクエリを減らすことなく、小さな範囲でのパフォーマンスを向上させることができますか?
私はPostgreSQLテーブルを持っており、それぞれに数百万のレコードと100を超えるフィールドがあります。
そのうちの 1 つは日付フィールドで、これによってクエリでフィルタリングします。この日付フィールドのインデックスを作成すると、小さな範囲の日付を読み取るクエリのパフォーマンスが向上しましたが、大きな範囲の日付ではパフォーマンスが低下しました...
どちらかを優先する必要がありますか?大きな範囲のクエリを減らすことなく、小さな範囲でのパフォーマンスを向上させることができますか?
PostgreSQL のクエリは、インデックスの情報だけでは答えられません。実行中のクエリの観点から行が表示されるかどうかは、メイン行自体に格納されます。したがって、何かにインデックスを追加し、それを使用するクエリを実行する場合、次の 2 つの手順が必要です。
したがって、インデックスを使用してクエリに応答すると、データ ブロックに直接アクセスして行をフェッチするよりも時間がかかる可能性があります。これが発生する最も一般的なケースは、実際にデータの大部分を取得している場合です。通常、テーブルの 20% 以上が使用されている場合は、順次アクセスするのが高速であると見なされます。プランナーは、アクセスされるのは 20% 未満であると考えている場合があるため、インデックスが優先されますが、それは正しくありません。これは、インデックスを追加するとクエリが遅くなる可能性がある 1 つの方法です。説明に基づいて、これはあなたが見ている状況である可能性があります-大きな範囲がオプティマイザーの見積もりよりも多くのテーブルに触れている場合、インデックスを使用すると正味の速度が低下する可能性があります.
これを把握するために、データベースは各テーブルの各列に関する統計を収集し、特定の WHERE 条件がインデックスを使用するのに十分選択的であるかどうかを判断します。テーブル全体を読み取らないことで非常に多くのブロックを保存する必要があるため、その上にインデックス I/O を追加することは、依然として最終的に有利であるという考えです。
この計算はうまくいかない可能性があり、場合によっては、テーブルを直接読み取った場合よりも多くの I/O を実行することになります。EXPLAIN ANALYZE を使用してクエリを実行すると、それらのほとんどの原因が明らかになります。「期待される」値と「実際の」数値が大きく異なる場合は、オプティマイザーがテーブルに不適切な統計を持っていたことを示している可能性があります。もう 1 つの可能性は、オプティマイザーがクエリの選択性について誤りを犯したことです。オプティマイザーは少数の行しか返さないと考えていましたが、実際にはほとんどのテーブルを返しています。ここでも、より良い統計は、それに取り組み始めるための通常の方法です。PostgreSQL 8.3 以前を使用している場合、デフォルトで収集される統計量は非常に少なくなります。
ワークロードによっては、このインデックスとテーブル スキャンのトレードオフがどこで発生するかを制御する、random_page_cost チューナブルも調整することになります。ただし、統計情報がチェックされた後に考慮すべきことはこれだけです。ここで調整できるいくつかの事項の概要については、PostgreSQL サーバーの調整を参照してください。
私はいくつかのことを試してみます:
この日付フィールドのインデックスを作成すると、小さな範囲の日付を読み取るクエリのパフォーマンスが向上しましたが、大きな範囲の日付ではパフォーマンスが低下しました...
そのインデックスを使用してテーブルをクラスタリングしてみてください。パフォーマンスの低下は、テーブル全体が大きな範囲で開かれていることが原因である可能性があります。その場合、そのインデックスに沿ってテーブルをクラスター化すると、ディスク シークが少なくなります。