PostgreSQL'deki bileşik dizindeki sütun sırası (ve sorgu sırası)


10

50K sıralı bir masam var. Aslında bir PostGIS tablosu.

Sorguda 4 bölüm var (1 zorunlu) (3 İsteğe bağlı)

  1. 4 lat, uzun kesişme kutusu (bir coğrafya dikdörtgeni) (st_intersects kullanıyorum) [Zorunlu]
  2. Bir tarih alanında Tarih Aralığı (min, maks.)
  3. Dosya türü (8 metin değerine kadar bir dizi) şu anda IN (.....) kullanarak, ancak gerekirse bir geçici tablo yapabilirsiniz. Bir çok insanın IN'i sevmediğini görüyorum.
  4. Ülke (metin değeri).

Yaklaşık 100 - 4.000 satır dönmesini bekliyorum

Tabloda bir bileşik dizin oluşturursam, önce hangi sütunu kullanmalıyım. İnce taneli muhtemelen konumdur (veriler dünyaya yayılmıştır). Şu anda GIST endeksi olarak var.

Diğer dizinler BTREE olacaktır.

Sezgim ince taneli ve son olarak kullanıldığını söylüyor. Örneğin, sadece 12 dosya türü vardır, bu nedenle dizin için çok büyük kovalar olacaktır.

PostgreSQL ve PostGIS guruları (sistemin içini bilen) ne diyor?


GÜNCELLEME:

Bu soruyu netleştireyim.

  1. Yapmam gereken işi kimsenin yapmasını istemiyorum. Zamanına çok saygı duyuyorum. Bu yüzden daha sonra açıklamaya analiz edeceğim.
  2. Aradığım tek şey bazı işaretçiler ve ipuçları ve yönergelerdi.
  3. Bu mükemmel küçük gönderiyi okudum: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes dizinler hakkında
  4. Normalde yaptığım şey 4 ayrı dizin oluşturmaktır (coğrafi kutu, ülke adı, dosya_türü ve tarih) ama bileşik bir sorgu ne yapacağını görmek istiyorum.

Bu varsayımlardan herhangi birinin yanlış olup olmadığını söyle. (Bileşik dizinler fikrinde oldukça yeniyim)

  1. Düzen önemlidir. İlk dizin olarak satırları en çok kesecek olanı seçin (benim durumumda basit bir çokgen veya çokgen çok iyi olan konum (coğrafya) en iyisini yapardı).
  2. Bazen sorgular dizinleri atlar. Ancak anahtar (# 1, # 2, # 3, # 4) ile bileşik bir sorgu oluşturursam, kullanıcı # 1, # 3 isteyen bir şey oluştursa bile, planlayıcı sipariş verdikleri için hala tek bileşik sorguyu kullanır korunur.
  3. Normalde üç BTREE sorgusu ve bir GIST (coğrafya türü için) oluştururdum. PostGIS, birden çok dizin türünden bir bileşik oluşturmayı desteklemez. Bu yüzden bileşik endeksi GIST kullanmam gerekecek. Ama bu bir şeylere zarar vermemeli.
  4. Bazı ek bileşik veya tek değer dizinleri oluşturursam, planlayıcı en akıllı olanı seçecek kadar akıllıdır .....
  5. Ülke Adı yaklaşık 250 farklı değere sahip olabilir ve açıkça konuma (geobox) güçlü bir şekilde bağlıdır, ancak satır boyutunu kesmek için bir sonraki en iyi dizin file_type ise bunu bir sonraki kullanmalıyım. Kullanıcıların sorgu kümelerinde sık sık ülke veya tarih kullanmasını beklemiyorum.
  6. 4 Anahtar bileşik bir dizin oluşturma konusunda endişelenmenize gerek yok büyük ölçüde dizin verilerinin boyutunu artıracaktır. Yani, tek anahtarlı bir dizin performans artışının% 90'ı olacaksa, bileşik hale getirmek için 3 öğe daha eklemek zarar vermez. Tersine, gerçekten her iki dizin oluşturmak gerekir. Tek bir coğrafya endeksi ve aynı zamanda bir bileşik endeks ve planlayıcının hangisinin en iyi olduğunu bulmasına izin verin ve dizin tablosunun boyutunu dikkate alacaktır.

Yine, kimseden benim çözümümü tasarlamasını istemiyorum, başkalarının çalışmalarından hoşlanmıyorum. Ama PostGreSQL belgelerinin uygulama hakkında bana söylemediği şeylere ihtiyacım var

[Göstermek için bir EXPLAIN sonucum olmamasının nedeni, bu 25K satır tablosunu 24M satır tablosundan oluşturmanız gerektiğidir. Düşündüğümden daha fazla zaman alıyor. Ben 1000 öğe grupları halinde şeyler kümeleme ve kullanıcı 25K satır tablo karşı sorgu izin. Ama bir sonraki sorum, MASTER 25M satır tablosuna gitmek ve bir şeyler çıkarmak için bu sorgunun sonuçlarını kullanmayı içerecek ve burada bileşik endeksin performansı gerçekten HIT olacak].


aşağıdaki örnek sorgu:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

AÇIKLAMA ANALİZİ sonuçları (herhangi bir bileşik indeks koymadım ve gördüğüm hızdan ihtiyacım olup olmadığını bilmiyorum).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))

2
Asıl sorguyu belirtin, lütfen.
ypercubeᵀᴹ

"3 isteğe bağlı", sorgunun 8 farklı varyasyonu olabileceği anlamına mı geliyor (2,3,4 seçeneğinin etkinleştirilip etkinleştirilmediğine bağlı olarak)?
ypercubeᵀᴹ

NEREDE 4 VE bileşen vardır. St_intersects üzerinde, diğerleri orada olabilir veya olmayabilir. Ama hepsinin mevcut olduğu dava ile ilgilenmek istiyorum.

2
Soruyu dba.se'ye taşımak için oy verdim, bu çoklu aralık koşullarıyla karmaşık bir sorgu.
ypercubeᵀᴹ

1
EXPLAIN ANALYZESorgu için göster .
Craig Ringer

Yanıtlar:


4

Çalışmamın bir parçası olarak oldukça büyük bir PostgreSQL veritabanı (diskte yaklaşık 120 gb, birkaç milyonlarca satırlık tablo) tutuyorum ve sorguları nasıl hızlandıracağına dair birkaç püf noktası topladım. Önce varsayımlarınızla ilgili bazı yorumlar:

  1. Evet, düzen önemlidir, ancak sadece gerçekten farklı olan ilk olan, geri kalanı ikinci sınıf dizinlerdir.
  2. Her zaman her ikisini de kullanacağından emin değilim, tahminim sorgu planlayıcısı # 1 kullanacak, sonra geri kalanıyla akıllıca bir şey yapacak.
  3. GIST ile hiçbir deneyimim yok.
  4. Evet, önce tüm dizinleri ekleyin, neyin en çok kullanıldığını ve neyin en iyi performansı verdiğini görün.
  5. Her ikisini de denemenizi ve neyin en iyi olduğunu ölçmenizi öneririm. Sql'yi farklı alt sorgularla, belki ülke ve zamanda bir arada yazmayı deneyin, ardından kesişim sorgusuna katılın. IN listesi, binlerce öğe uzun olmadığı sürece, IN yan tümceleri ile ilgili herhangi bir performans sorunu fark etmedim. Benim tahminim, mevcut giriş kriterlerine bağlı olarak özel olarak ayarlanmış birkaç farklı sorgunun en iyi sonuçları vereceğidir.
  6. 4 yönlü endeks oluşturmamayı öneriyorum. Bir tane oluşturmayı deneyin ve sonra boyutu kontrol edin, gerçekten çok büyük olabilirler. Deneyimlerime göre, dört adet 1 anahtarlı dizin neredeyse tek bir 4 yönlü dizin kadar hızlı olmuştur. Bazı belirli sorgular için iyi çalışan bir hile kısmi dizinlerdir, yani şöyle bir şey:

    INDEX ON CREATE ON table_x (anahtar1, anahtar2, anahtar3) NEREDE some_x_column = 'XXXX';

Eklenecek veya kaldırılacak dizinleri bulmanıza yardımcı olması için .psqlrc dosyamda sorgularla takma adlar oluşturdum. GitHub: .psql adresine göz atabilirsiniz.

Ben seq_scans ve: bigtables çok kullanın ve sonra tablo hakkında ayrıntılı bilgi almak için \ d table_name. Bazı değişiklikleri yaptıktan sonra istatistikleri sıfırlamayı unutmayın, pg_stat_reset () öğesini seçin;


1
Bunlar mükemmel ipuçları. Tavsiyeni aldım ve daha sonra bunu sürdürdüğümüz çok daha büyük bir masada (43 milyon sıra) bir deney yapmak için kullandım. Sonuçlar şuradadır
Dr.YSG

1

Ben (bir şey varsa) yardımcı olma olasılığı en muhtemel şey gist dizinine 2. sütun olarak product_type eklemek olacağını düşünüyorum. Ancak, tipik / sorunlu sorgularınız için AND koşullarının (ayrı ayrı) her biriyle kaç satır eşleştiğini bilmeden, yalnızca tahmin edebiliriz.

Buna yaklaştığımda, yaptığım ilk şey, sorguyu WHERE deyiminin yalnızca bir koşulu, her biri sırayla, EXPLAIN ANALYZE altında alınan basitleştirilmiş biçimde çalıştırmaktır. Her biri için hem tahmini satırlara hem de gerçek satırlara bakın.


Yukarıdaki güncellememe bakın, ancak bana iyi bir ipucu verdiğinizi, satır çıktısını en hızlı şekilde kesen dizinleri sipariş etmeyi düşünün. Bu doğru mu?
Dr.YSG
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.