2011-12-19 9 views
7

インデックス付きの単語テーブル(language_id、state)があります。ここでANALYZE EXPLAINの結果は次のとおりです。ポストグラムでLIMITが使用されている場合はインデックスが使用されません

制限なし

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL); 

Bitmap Heap Scan on words (cost=10800.38..134324.10 rows=441257 width=96) (actual time=233.257..416.026 rows=540556 loops=1) 
Recheck Cond: ((language_id = 27) AND (state IS NULL)) 
-> Bitmap Index Scan on ls (cost=0.00..10690.07 rows=441257 width=0) (actual time=230.849..230.849 rows=540556 loops=1) 
Index Cond: ((language_id = 27) AND (state IS NULL)) 
Total runtime: 460.277 ms 
(5 rows) 

リミット100は

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL) LIMIT 100; 

Limit (cost=0.00..51.66 rows=100 width=96) (actual time=0.081..0.184 rows=100 loops=1) 
-> Seq Scan on words (cost=0.00..227935.59 rows=441257 width=96) (actual time=0.080..0.160 rows=100 loops=1) 
Filter: ((state IS NULL) AND (language_id = 27)) 
Total runtime: 0.240 ms 
(4 rows) 

なぜこの出来事はありますか?すべてのケースでインデックスを使用するにはどうすればよいですか?

ありがとうございました。

+4

ORDER BYのないLIMITは、制限された(意図しない)値のようです。どの100行が返されますか? –

+0

BTW:language_id = 17 AND status IS NULL句の選択性は何ですか?単語表の合計サイズは? – wildplasser

+0

true ...注文はID DESCで発生します。それはそれを遅くすることができますか?その列にインデックスが必要ですか? @wildplasserの合計サイズは1000万行、選択率は約500,000行です – alste

答えて

7

私は、PostreSQLのクエリプランナーは、2番目のケースではLIMITを持つものを考えていると思っています。[LIMIT]が小さすぎるのでインデックスを適用する価値はありません。だからそれは問題ではない。

+0

あなたは正しいですが、どうすればこれを避けることができますか?実際に私はjsonbジンインデックスを使用しており、このインデックスは使用されておらず、巨大な時間を費やしていません。 – Anurag

0

2つのクエリが異なる行数を返すのも奇妙です。私はあなたが挿入されていると思う... Uhm、あなたがサブセレクトをしたら?制限なし

select * from (select ...) limit 100; 
+1

"(5 rows)"は、クエリが返す行の数ではなく、explainプランの行数を示します – Anna

3

:= 1つの合計ランタイム行= 540556のループ:制限付き460.277ミリ秒

:行= 100のループ= 1つの合計ランタイム:0.240ミリ

私は、問題が表示されませんここに。クエリで行が500Kになる場合は、より多くの時間が必要になります。

3

Using EXPLAINQuery Planningに関するPostgreSQLのドキュメントを見てください。照会プランナーがLIMIT 100のケースでインデックススキャンで順次スキャンを優先させるのは、シーケンシャルスキャンが安価であるためです。

クエリにはORDER BY句がないため、プランナはフィルタ条件に一致する最初の100(ランダム)行でOKです。索引スキャンでは、最初に索引ページを読み取ってから、その行をフェッチするためにデータ・ページを読み取る必要があります。順次スキャンでは、行をフェッチするためにデータページを読み取るだけで済みます。あなたのケースでは、テーブルの統計は、フィルタ条件に一致する十分な(ランダムな)行があることを示唆しているようです。 100行を取得するための順次ページ読取りのコストは、最初に索引を読んでから実際の行をフェッチするコストよりも安いと考えられます。限度を引き上げるときや、フィルタ条件に一致する行が少なくなるときは、別のプランが表示されることがあります。プランナーがランダムに読んだページ(random_page_costを)シーケンシャルページの読み込み(をseq_page_cost)の4倍のコストのコストを考慮し、デフォルトの設定では

。これらの設定を調整してクエリプランを調整することができます(たとえば、データベース全体がRAMにある場合、ランダムページ読み取りはシーケンシャルページ読み取りよりも高価ではなく、インデックススキャンを優先する必要があります)。それはグローバルベースでのスキャンの特定の種類を有効/無効にすることは可能ですが

set enable_seqscan = [on | off] 
set enable_indexscan = [on | off] 

これはのみ使用してくださいアドホック用:あなたはまた、スキャンの特定の種類を無効にする/例えば有効にすることで、別のクエリ・プランを試してみることができますセッションごとのデバッグまたはトラブルシューティング

また、クエリプランをテストする前にVACUUM ANALYZE wordsを実行してください。そうしないと、テスト間で実行される自動バキューム(autovaccum)が結果に影響する可能性があります。

関連する問題