web-dev-qa-db-ja.com

なぜpkeyインデックススキャンで非常に多くのループが発生するのですか?

すべてのインデックスが設定されているにもかかわらず、クエリの実行が非常に遅くなります。

SELECT * FROM "entry"
    INNER JOIN "entrytag" ON ("entry"."id" = "entrytag"."entry_id")
    WHERE "entrytag"."tag_id" = 323456
    ORDER BY "entry"."date"
    DESC LIMIT 10'

説明でループが多すぎますが、なぜですか?これを修正する方法?

Limit  (cost=1241.85..1241.87 rows=10 width=666) (actual time=23576.449..23576.454 rows=10 loops=1)
  ->  Sort  (cost=1241.85..1242.10 rows=99 width=666) (actual time=23576.446..23576.447 rows=10 loops=1)
        Sort Key: entry.date DESC
        Sort Method: top-N heapsort  Memory: 31kB
        ->  Nested Loop  (cost=0.87..1239.71 rows=99 width=666) (actual time=0.168..22494.187 rows=989105 loops=1)
              ->  Index Scan using entrytag_tag_id_row_idx on entrytag  (cost=0.44..402.17 rows=99 width=4)
                  (actual time=0.093..535.664 **rows=989105** loops=1)
                    Index Cond: (tag_id = 323456)
              ->  Index Scan using entry_pkey on entry  (cost=0.43..8.45 rows=1 width=666) 
l time=0.020..0.021 rows=1 **loops=989105**)
                    Index Cond: (id = entrytag.entry_id)
Planning time: 0.829 ms
Execution time: 23576.504 ms

テーブルentryにあるインデックス:

('id', 'date', ...other irrelevant cols)
('date', ...other irrelevant cols)

関連付けテーブルentrytag

(tag_id, entry_id)
(tag_id, row)  -- this index is used according to the explain

PostgreSQL v 9.5。多くの行があり、dbは非常に大きいです。他のタグに対する同じクエリ(同じ数のエントリを持つ)は、ほんの数秒しかかかりません。そのような巨大な行とループのカウントはありません。

4
Mary

問題はここにあります

Index Scan using entrytag_tag_id_row_idx on entrytag
    (cost=0.44..402.17 rows=99 width=4)
    (actual time=0.093..535.664 rows=989105 loops=1)

あなたの統計は

WHERE "entrytag"."tag_id" = 323456

あなたのプランナーははるかに少ないと考えていますtag_id=323456あります。 ANALYZE entrytag;、そして再試行します。またはupping統計。

ALTER TABLE entrytag
  ALTER COLUMN tag_id
  SET STATISTICS 1000;

次に、ANALYZE entrytag;と再試行します。悪い統計の典型的なケースのように聞こえます。

スキーマを改善したり、非正規化したりできます。 100万行を結合、選択、および注文しています。それはすぐにはいきません。

2
Evan Carroll