Büyük tabloda yavaş dizin taramaları


12

PostgreSQL 9.2 kullanarak, nispeten büyük bir tablo (200+ milyon satır) yavaş sorguları ile ilgili sorunlar var. Çılgınca bir şey denemiyorum, sadece tarihi değerler katıyorum. Sorgu ve sorgu planı çıktısı aşağıdadır.

Tablo düzenim:

                                   Table "public.energy_energyentry"
  Column   |           Type           |                            Modifiers
-----------+--------------------------+-----------------------------------------------------------------
 id        | integer                  | not null default nextval('energy_energyentry_id_seq'::regclass)
 prop_id   | integer                  | not null
 timestamp | timestamp with time zone | not null
 value     | double precision         | not null
Indexes:
    "energy_energyentry_pkey" PRIMARY KEY, btree (id)
    "energy_energyentry_prop_id" btree (prop_id)
    "energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
    "energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED

Veriler 2012-01-01'den bugüne kadar değişmektedir ve sürekli olarak yeni veriler eklenmektedir. prop_idYabancı anahtarda eşit olarak dağılmış yaklaşık 2.2k farklı değer vardır .

Satır tahminlerinin çok uzakta olmadığını fark ettim, ancak maliyet tahminleri faktör 4x daha büyük görünüyor. Bu muhtemelen bir sorun değil, ancak bu konuda yapabileceğim bir şey var mı?

Tablo her zaman bellekte olmadığından, disk erişiminin sorun olabileceğini düşünüyorum.

EXPLAIN ANALYZE 
SELECT SUM("value") 
FROM "energy_energyentry" 
WHERE 
  "prop_id"=82411 
  AND "timestamp">'2014-06-11' 
  AND "timestamp"<'2014-11-11'
;
 Aggregate  (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1)
   ->  Index Scan using energy_energyentry_prop_id_timestamp_idx on  energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1)
         Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone))
 Total runtime: 51504.841 ms

Bunu nasıl daha hızlı hale getireceğinize dair herhangi bir öneriniz var mı?
Ben de sadece garip bir şey yapmadığımı duyuyorum.


1
Lütfen tablonuzun nasıl göründüğünü, hangi dizinlere sahip olduğunu ve verilerin yayılmasını belirtin.
Colin 't Hart

Sorduğunuz ek bilgileri ekledim. Bir şey kaçırıp kaçırmadığımı bilmiyorum.
Exelian

2
Garip: Açıklamanız analiz gösterir prop_time_idx, ancak tablo tanımı gösterir entry_prop_id_timestamp_idx. Bu aynı indeks mi? Lütfen düzelt.
Colin 't Hart

'Maliyet tahminleri, maliyet sayılarının gerçek zamanın yaklaşık 4 katı olduğu gerçeğine 4x daha büyük bir faktör gibi görünüyorsa' , lütfen ikisinin birbiriyle hiçbir ilgisi olmadığını unutmayın. Maliyet yalnızca bir tahmindir ve sorgu optimize edicinin en iyi görünümlü planı seçmesine yardımcı olur. Bu bağlamın dışında, genellikle anlamsız bir değerdir.
dezso

1
Tarih aralığınız tablonun yüzde kaçını temsil ediyor (değerlerini dikkate almadan prop)? Sadece küçük bir yüzde, belki bir endeksi ("timestamp", prop)daha iyi olurdu. Aynı satır aralığı sütunlarına ( propsizin durumunuzda) sahip birden çok dizin de genellikle gereksizdir.
Colin 't Hart

Yanıtlar:


10

Tablonuz büyük ve tüm tabloyu kapsayan herhangi bir dizin de. Varsayım:

  • sadece yeni veriler (ile timestamp = now()) girilir
  • mevcut satırlar ne değiştirilir ne de silinir.
  • 2012-01-01 tarihinden bu yana verileriniz var ancak sorgular ağırlıklı olarak bu yıl (?)

Kısmi, çok sütunlu (kapsayan!) Bir dizin önerirsiniz :

CREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0';  -- adapt to your needs

Yalnızca düzenli olarak sorgulanan zaman aralığını ekleyin. Yeni girdilerle etkinlik zamanla bozulur. Dizini zaman zaman yeniden oluşturun. (Sorgularınızı uyarlamanız gerekebilir.) Aşağıdaki bağlantılı cevaba bakınız.

Son sütun değeri yalnızca bundan sadece dizin taramaları almak için dahil edilir . Agresif otovakum ayarı, daha önce bahsedilen @jjanes gibi görünürlük haritasını güncel tutarak yardımcı olabilir .

Kısmi endeks RAM'a daha kolay sığmalı ve orada daha uzun kalmalıdır.

WHEREPlanlayıcının dizinin sorgu için geçerli olduğunu anlamasını sağlamak için bu koşulu sorgulara eklemeniz gerekebilir :

SELECT sum(value) AS sum_value
FROM   energy_energyentry
WHERE  prop_id = 82411 
AND   "timestamp" > '2014-06-11 0:0' 
AND   "timestamp" < '2014-11-11 0:0'
AND   "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed

Sorgunuz çok sayıda satır ( rows=13578) topladığından , yalnızca dizin içeren bir taramada bile bu biraz zaman alacaktır. Yine de 50 saniyeye yakın bir yerde olmamalıdır. Herhangi bir yarım donanımda bir saniyeden az.

İlgili (ancak yoksayın CLUSTERve FILLFACTORbundan yalnızca dizin taramaları alabiliyorsanız her ikisi de önemsizdir) :

Kenara:
Eğer bu yana şu anda üzerinde bir dizin var (prop_id, "timestamp"), sadece ek endeksi (prop_id)'s değerinde daha pahalı olabilir:


Postgres artık BRIN dizinlerini desteklediğine göre, bu yararlı olur mu? Postgres üzerindeki verilerde yaklaşık 140 milyon satır depolamayı planlıyorum, BRIN bu kadar büyük tablo için kullanılacak doğru dizin mi?
Arya

2

Dizini (prop_id, "timestamp", "value") yaparsanız, tabloyu ziyaret etmeden değeri hesaplamak için yalnızca dizin içeren bir tarama kullanabilir. Bu, rasgele disk erişiminden büyük tasarruf sağlayabilir.

En fazla yararı elde etmek için masayı vakumlama konusunda agresif olmanız gerekir. Varsayılan otomatikvac ayarları, yalnızca dizin içeren taramaları etkin bir şekilde desteklemek istediğiniz yalnızca ekleme tabloları için yeterince agresif değildir.


Değer eklemek gerçekten ilginç olabilir, bunun hızlanıp hızlanmayacağına bir göz atacağım. Bakabileceğim vakum ayarları veya dokümantasyon için herhangi bir öneriniz var mı?
Exelian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.