150万行のテーブルに対する比較的単純なクエリがあります。
SELECT mtid FROM publication
WHERE mtid IN (9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
出力:
Limit (cost=8.84..12.86 rows=1 width=8) (actual time=0.985..0.986 rows=1 loops=1) -> Bitmap Heap Scan on publication (cost=8.84..12.86 rows=1 width=8) (actual time=0.984..0.985 rows=1 loops=1) Recheck Cond: ((mtid = 9762715) OR (last_modifier = 21321)) -> BitmapOr (cost=8.84..8.84 rows=1 width=0) (actual time=0.971..0.971 rows=0 loops=1) -> Bitmap Index Scan on publication_pkey (cost=0.00..4.42 rows=1 width=0) (actual time=0.295..0.295 rows=1 loops=1) Index Cond: (mtid = 9762715) -> Bitmap Index Scan on publication_last_modifier_btree (cost=0.00..4.42 rows=1 width=0) (actual time=0.674..0.674 rows=0 loops=1) Index Cond: (last_modifier = 21321) Total runtime: 1.027 ms
これまでのところ、高速で、使用可能なインデックスを使用しています。
ここで、クエリを少しだけ変更すると、結果は次のようになります。
SELECT mtid FROM publication
WHERE mtid IN (SELECT 9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
出力は次のようになります。
Limit (cost=0.01..2347.74 rows=5000 width=8) (actual time=2735.891..2841.398 rows=1 loops=1) -> Seq Scan on publication (cost=0.01..349652.84 rows=744661 width=8) (actual time=2735.888..2841.393 rows=1 loops=1) Filter: ((hashed SubPlan 1) OR (last_modifier = 21321)) SubPlan 1 -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1) Total runtime: 2841.442 ms
それほど速くなく、seqスキャンを使用しています...
もちろん、アプリケーションによって実行される元のクエリは少し複雑で、さらに遅くなります。もちろん、休止状態で生成された元のクエリはそう(SELECT 9762715)
ではありませんが、それでも速度は低下しません(SELECT 9762715)
。クエリはhibernateによって生成されるため、それらを変更することは非常に困難であり、一部の機能は使用できません(たとえばUNION
、使用できないため、高速になります)。
質問
- 2番目のケースでインデックスを使用できないのはなぜですか?それらはどのように使用できますか?
- 他の方法でクエリのパフォーマンスを改善できますか?
追加の考え
最初のケースは手動でSELECTを実行し、結果のリストをクエリに入れることで使用できるようです。IN()リストに5000の数値があっても、2番目のソリューションより4倍高速です。しかし、それは間違っているように見えます(また、100倍も高速になる可能性があります:))。クエリプランナーがこれら2つのクエリに対してまったく異なる方法を使用する理由は完全に理解できないため、この問題に対するより良い解決策を見つけたいと思います。
(SELECT 9762715)
。
(SELECT 9762715)
。休止状態の質問:実行できますが、オンザフライで翻訳されるユーザー定義の休止状態基準クエリがあるため、深刻なコードの書き換えが必要です。したがって、本質的には、休止状態を変更することになります。これは、多くの可能な副作用を伴う巨大な事業です。
JOIN
代わりにを生成するように、どういうわけかコードを書き換えることができますIN ()
か?また、publication
最近分析されましたか?