Nest Nest indesiderato vs. Hash Iscriviti in PostgreSQL 9.6


13

Ho un problema con la pianificazione delle query PostgreSQL 9.6. La mia query è simile alla seguente:

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)

Ho abilitato la sicurezza a livello di riga per le tabelle utilizzate in precedenza.

L'ho fatto VACUUM ANALYZEprima di eseguire le query, ma non ha aiutato.

So che non è una buona pratica set enable_nestloop = Falsee altre opzioni simili per il planner. Ma come potrei "convincere" il pianificatore a utilizzare i hash join senza disabilitare i loop nidificati?

Riscrivere la query è un'opzione.

Se eseguo la stessa query con un ruolo che ignora RLS, viene eseguita molto velocemente. La politica di sicurezza a livello di riga è simile alla seguente:

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
);

Qualsiasi idea o suggerimento sarebbe molto apprezzato.


Solo un po 'confuso: perché averlo AND properties."TYPE_ID" IN (6);e no = 6;?
Vérace,

2
@Vérace while = è usato più ampiamente, entrambi vengono planati allo stesso modo. La mia ipotesi è che stia giocando con più di un valore o che un ORM sia un po 'pigro.
Evan Carroll,

Risposte:


15

Quello che sta succedendo qui è che il Nested Loop è lontano da un lato. I loop nidificati funzionano davvero bene quando un lato è molto piccolo, come restituire una riga. Nella tua query, il planner si armeggia qui e stima che un Hash Join restituirà solo una riga. Invece, quel hash join (property_id = id) restituisce 1.338 righe. Ciò costringe a eseguire 1.388 loop sull'altro lato del Nested Loop che ha già 3.444 file. Questo è un vero successo quando te ne aspetti solo uno (che non è nemmeno un gran "giro"). Anywayy ..

Un ulteriore esame mentre ci spostiamo verso il basso mostra che l'Hash Join è davvero ostacolato dalle stime che ne derivano,

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

PostgreSQL si aspetta che restituisca una riga. Ma non lo fa. E questo è davvero il tuo problema. Quindi alcune opzioni qui, che non comportano l'estrazione di una mazza e la disabilitazionenested_loop

  • È possibile aggiungere uno o due indici propertiesper aiutarlo potenzialmente a saltare completamente la scansione seq o a stimare meglio il rendimento.

    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;
  • In alternativa, è possibile spostare gli elementi delle proprietà in un CTE o sottoselezionare con OFFSET 0cui creare un recinto.

    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
    )
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.