1.5M satır içeren bir tabloda nispeten basit bir sorgu var:
SELECT mtid FROM publication
WHERE mtid IN (9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
çıktı:
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
Şimdiye kadar iyi, hızlı ve mevcut endeksleri kullanır.
Şimdi, bir sorguyu biraz değiştirirsem sonuç şu olur:
SELECT mtid FROM publication
WHERE mtid IN (SELECT 9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
Çıktısı:
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
Çok hızlı değil ve seq taraması kullanıyor ...
Tabii ki, uygulama tarafından çalıştırılan orijinal sorgu biraz daha karmaşık ve hatta daha yavaş ve elbette hazırda bekletilen oluşturulan orijinal değil (SELECT 9762715)
, ama bunun için bile yavaşlık var (SELECT 9762715)
! Sorgu hazırda bekletme tarafından oluşturulur, bu nedenle bunları değiştirmek oldukça zordur ve bazı özellikler mevcut değildir (örneğin UNION
, hızlı olan) kullanılamaz).
Sorular
- İndeks ikinci durumda neden kullanılamıyor? Nasıl kullanılabilirler?
- Sorgu performansını başka bir şekilde artırabilir miyim?
Ek düşünceler
İlk durumu el ile bir SELECT yaparak ve ardından ortaya çıkan listeyi sorguya koyarak kullanabiliriz. IN () listesindeki 5000 rakamla bile ikinci çözümden dört kat daha hızlıdır. Ancak, sadece YANLIŞ görünüyor (ayrıca, 100 kat daha hızlı olabilir :)). Neden sorgu planlayıcısı bu iki sorgu için tamamen farklı bir yöntem kullanıyor tamamen anlaşılmaz, bu yüzden bu soruna daha güzel bir çözüm bulmak istiyorum.
(SELECT 9762715)
.
(SELECT 9762715)
. Hazırda bekletme sorusuna: yapılabilir, ancak anında çevrilen kullanıcı tanımlı hazırda bekletme ölçütleri sorgularımız olduğu için ciddi kod yeniden yazma gerektirir. Aslında, birçok olası yan etkisi olan büyük bir girişim olan kış uykusunu değiştireceğiz.
JOIN
yerine oluştururIN ()
mu? Ayrıca,publication
son zamanlarda analiz edildi mi?