PostgreSQL 9.6'da İstenmeyen Nest Loop ve Hash'e Katılın


13

PostgreSQL 9.6 sorgu planlamasında sorun yaşıyorum. Sorgum şöyle görünüyor:

SET role plain_user;

SELECT properties.*
FROM properties
JOIN entries_properties
  ON properties.id = entries_properties.property_id
JOIN structures
  ON structures.id = entries_properties.entry_id 
WHERE structures."STRUKTURBERICHT" != ''
  AND properties."COMPOSITION" LIKE 'Mo%'
  AND (
    properties."NAME" LIKE '%VASP-ase-preopt%'
    OR properties."CALCULATOR_ID" IN (7,22,25)
  )
AND properties."TYPE_ID" IN (6)

Yukarıda kullanılan tablolar için Satır Düzeyinde Güvenlik etkin.

VACUUM ANALYZESorguları çalıştırmadan önce yaptım , ama yardımcı olmadı.

Plancı için iyi bir uygulama olmadığını set enable_nestloop = Falseve benzer herhangi bir seçenek olmadığını biliyorum . Ancak, planlayıcıyı iç içe döngüleri devre dışı bırakmadan karma birleştirmeleri kullanmaya nasıl "ikna edebilirim"?

Sorguyu yeniden yazmak bir seçenektir.

Aynı sorguyu RLS'yi atlayan bir rol altında çalıştırırsam, çok hızlı yürütülür. Satır düzeyinde güvenlik ilkesi şöyle görünür:

CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
  (
    properties.ouid = get_current_user_id()
    AND properties.ur
  )
  OR (
    properties.ogid in (select get_current_groups_id())
    AND properties.gr
  )
  OR properties.ar
);

Herhangi bir fikir veya öneri büyük mutluluk duyacağız.


Biraz karışık: neden var AND properties."TYPE_ID" IN (6);ve olmasın = 6;?
Vérace

2
@ Vérace = daha geniş olarak kullanılırken, ikisi de aynı şekilde planlanır. Benim varsayımım, birden fazla değerle oynadığı ya da bir ORM'nin biraz tembel olduğu.
Evan Carroll

Yanıtlar:


15

Burada olan, Nested Loop'un bir tarafta yolunun kapalı olmasıdır. İç içe Döngüler , bir taraf çok küçük olduğunda (örneğin bir satır döndürme) gerçekten iyi çalışır . Sorgunuzda, planlayıcı burada yankılanıyor ve Hash Join'ın yalnızca bir satır döndüreceğini tahmin ediyor. Bunun yerine bu Karma Birleştirme (property_id = id) 1.338 satır döndürür. Bu, 1,338 döngüyü, zaten 3,444 satırı olan Yuvalanmış Döngünün diğer tarafında çalışmaya zorlar. Bu sadece bir tane beklediğinizde bir hella-lot (ki bu bir "döngü" bile değil). Anywayy ..

Aşağı doğru ilerlediğimizde yapılacak daha ileri incelemeler, Karma Birleşimi'nin bundan kaynaklanan tahminlerle gerçekten doluydu,

Filter: (((properties."COMPOSITION")::text ~~ 'Mo%'::text) AND (((properties."NAME")::text ~~ '%VASP-ase-preopt%'::text) OR (properties."CALCULATOR_ID" = ANY ('{7,22,25}'::integer[]))))

PostgreSQL bunun bir satır döndürmesini bekliyor. Ama öyle değil. Ve bu gerçekten senin sorunun. Burada bazı seçenekler, bir balyoz çekici ve devre dışı bırakmayı içermiyornested_loop

  • propertiesSıralı taramayı tamamen atlamasına veya geri dönüşü daha iyi tahmin etmesine yardımcı olması için bir veya iki dizin ekleyebilirsiniz .

    CREATE INDEX ON properties USING ( "TYPE_ID", "CALCULATOR_ID" );
    -- the gist_trgm_ops may or may not be needed depending on selectivity of above.
    CREATE INDEX ON properties USING GIST (
      "COMPOSITION" gist_trgm_ops,
      "NAME"        gist_trgm_ops
    );
    ANALYZE properties;
    
  • Alternatif olarak, özellik öğelerini OFFSET 0bir çit oluşturan bir CTE'ye veya alt seçime taşıyabilirsiniz .

    WITH t AS (
      SELECT *
      FROM properties.
      WHERE "COMPOSITION" LIKE 'Mo%'
      AND (
        "NAME" LIKE '%VASP-ase-preopt%'
        OR "CALCULATOR_ID" IN (7,22,25)
      )
      AND "TYPE_ID" IN (6)
    )
    SELECT * FROM structures
    JOIN t ON (
      structures.id = entries_properties.entry_id
    )
    
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.