tl; dr item_id
にインデックスを追加する必要があります 。 Postgresインデックス作成の「黒魔術」は、11で説明されています。インデックス
。
(topic_id、item_id)
に複合インデックスがあります 列の順序は重要です。 Postgresはこれを使用して、 topic_id
のクエリにインデックスを付けることができます 、両方の topic_id
に対するクエリ およびitem_id
、ただし item_id
ではありません(または効率が低下します) 一人で。
-- indexed
select *
from topics_items
where topic_id = ?
-- also indexed
select *
from topics_items
where topic_id = ?
and item_id = ?
-- probably not indexed
select *
from topics_items
where item_id = ?
これは、(topic_id、item_id)
のような複合インデックスが原因です。 最初にトピックIDを格納し、次にそのトピックIDも持つアイテムIDを格納します。このインデックスでアイテムIDを効率的に検索するには、Postgresは最初にトピックIDで検索を絞り込む必要があります。
Postgresはできます 努力する価値があると思われる場合は、インデックスを逆にします。可能なトピックIDの数が少なく、可能なインデックスIDの数が多い場合、各トピックIDでインデックスIDが検索されます。
たとえば、10個の可能なトピックIDと1000個の可能なアイテムIDがあり、インデックスが(topic_id、index_id)
であるとします。 。これは、明確にラベル付けされたトピックIDバケットが10個あり、それぞれに明確にラベル付けされたアイテムIDバケットが1000個あるようなものです。アイテムIDバケットにアクセスするには、各トピックIDバケットの内部を調べる必要があります。 where item_id =23
でこのインデックスを使用するには Postgresは、10個のトピックIDバケットのそれぞれで、アイテムID23のすべてのバケットを検索する必要があります。
ただし、1000個の可能なトピックIDと10個の可能なアイテムIDがある場合、Postgresは1000個のトピックIDバケットを検索する必要があります。ほとんどの場合、代わりに全表スキャンを実行します。この場合、インデックスを逆にして(item_id、topic_id)
にします。 。
これは、適切なテーブル統計があるかどうかに大きく依存します。つまり、自動バキュームが正しく機能していることを確認します。
したがって、1つの列の変動が他の列よりもはるかに少ない場合は、2つの列に対して1つのインデックスを使用する必要があります。
Postgresは、クエリを実行すると思われる場合は、複数のインデックスを使用することもできます。より速く
。たとえば、 topic_id
にインデックスがある場合 およびitem_id
のインデックス 、できます 両方のインデックスを使用して、結果を組み合わせます。たとえば、 where topic_id=23またはitem_id=42
topic_idインデックスを使用してトピックID23を検索し、item_idインデックスを使用してアイテムID 42を検索し、結果を組み合わせることができます。
これは通常、複合(topic_id、item_id)
を使用するよりも時間がかかります。 索引。また、単一のインデックスを使用するよりも遅くなる可能性があるため、Postgresが複数のインデックスを使用しないことを決定しても驚かないでください。
一般に、bツリーインデックスの場合、2つの列がある場合、3つの可能な組み合わせがあります。
- a + b
- a
- b
そして、2つのインデックスが必要です。
- (a、b)-aおよびa + b
- (b)-b
(a、b)コード> aとa+bの両方の検索をカバーします。
(b)コード>
b
の検索について説明します 。
3つの列がある場合、7つの可能な組み合わせがあります。
- a + b + c
- a + b
- a + c
- a
- b + c
- b
- c
ただし、必要なインデックスは3つだけです。
- (a、b、c)-a、a + b、a + b + c
- (b、c)-b、b + c
- (c、a)-c、c + a
ただし、実際には、3つの列にインデックスを作成することは避けたいと思うでしょう。多くの場合、遅い 。実際に欲しいのはこれです。
- (a、b)
- (b、c)
- (c、a)
インデックスからの読み取りは、テーブルからの読み取りよりも遅くなります。インデックスで読み取る必要のある行数を減らす必要がありますが、Postgresで必要以上のインデックススキャンを実行する必要はありません。