LIMIT付きの遅いORDER BY


11

私はこのクエリを持っています:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount

私はそれに満足しています:

"Sort  (cost=3842.56..3847.12 rows=1826 width=123) (actual time=1.915..2.084 rows=1307 loops=1)"
"  Sort Key: displaycount"
"  Sort Method: quicksort  Memory: 206kB"
"  ->  Bitmap Heap Scan on location  (cost=34.40..3743.64 rows=1826 width=123) (actual time=0.788..1.208 rows=1307 loops=1)"
"        Recheck Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"        ->  Bitmap Index Scan on location_lower_idx  (cost=0.00..33.95 rows=1826 width=0) (actual time=0.760..0.760 rows=1307 loops=1)"
"              Index Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2.412 ms"

しかし、LIMITを追加すると、実行に2秒以上かかります。

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount 
limit 20

説明:

"Limit  (cost=0.00..1167.59 rows=20 width=123) (actual time=2775.452..2775.643 rows=20 loops=1)"
"  ->  Index Scan using location_displaycount_index on location  (cost=0.00..106601.25 rows=1826 width=123) (actual time=2775.448..2775.637 rows=20 loops=1)"
"        Filter: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2775.693 ms"

ORDER BYとLIMITの問題だと思います。PostgreSQLにインデックスを使用させ、最後に順序を付けるにはどうすればよいですか?

サブクエリは役に立ちません:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
    order by displaycount
) t 
LIMIT 20;

または:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw'))
) t 
order by displaycount 
LIMIT 20;

回答:


12

これはあなたのクエリを修正すると思います:

SELECT * 
FROM   location 
WHERE     to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
ORDER  BY to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) DESC
         ,displaycount 
LIMIT  20;

WHERE条件をORDER BY句の最初の要素として繰り返します-これは論理的に冗長ですが、クエリプランナーがインデックスに従って行を処理する方が良いとは思わないようにする必要がありますlocation_displaycount_index-これははるかに高価になることがわかります。

根本的な問題は、クエリプランナーがWHERE条件の選択性やコストを明らかに誤って判断していることです。それがなぜなのかを推測できるだけです。

あなたはautovacuumを実行ANALYZEしていますか-これはあなたのテーブルで実行することにも注意を払うべきですか?それにより、テーブル統計は最新ですか?実行した場合の影響:

ANALYZE location;

そしてさらに試みる?

また、@@オペレーターの選択性が誤って判断されている可能性もあります。論理的な理由で見積もることは非常に難しいと思います。


私のクエリが問題を解決すべきではなく、一般に根本的な理論を検証するには、次の2つのことのいずれかを実行します。

後者は煩わしさが少なく、現在のセッションにのみ影響します。より高速な計画で使用されるメソッドbitmap heap scanbitmap index scanオープン状態を残します。
次に、クエリを再実行します。

ところで:理論が正しい場合は、FTS条件の検索語句の選択性が低くなるため、予想どおりではなく、クエリがはるかに高速になります(現在のとおり)。それを試してみてください。


1
クエリは機能します。indexscanをオフにしても機能します。ANALYZEが機能しません。包括的な回答ありがとうございました。
ziri

0

LIMIT postgresqlを使用する場合、行のサブセットのみを取得するために最適になるように調整します。残念ながら、それはどういうわけかあなたのケースでは間違った選択をします。これは、テーブルの統計が古すぎることが原因である可能性があります。VACUUM ANALYZE locationを発行して、統計を更新してみてください。

インデックスの使用を強制するには、通常、順次スキャンの使用を禁止します(enable_seqscan = falseを設定)。ただし、あなたの場合、それはシーケンシャルスキャンを実行していないので、LIMITを使用してクエリの別のインデックスに切り替えるだけです。

分析が役に立たない場合は、使用しているpostgresqlのバージョンを確認できますか?また、テーブルには何行ありますか?


分析は役に立ちませんでした。テーブルには約36000行あり、私はpostgresql 9.1を使用しています。
ziri
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.