PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Unisci due tabelle usando id e discendenti da tree like table

Integra query

Migliorando la logica in più punti, puoi integrare l'intera operazione in un'unica query. Il wrapping in una funzione SQL è facoltativo:

CREATE OR REPLACE FUNCTION f_elems(_action_id integer)
  RETURNS SETOF integer AS
$func$
   WITH RECURSIVE l AS (
      SELECT a.category_id, l.local_id
      FROM   action a
      JOIN   local  l USING (local_id)
      WHERE  a.action_id = $1

      UNION ALL 
      SELECT l.category_id, c.local_id
      FROM   l
      JOIN   local c ON c.parent_id = l.local_id  -- c for "child"
      )
   SELECT e.element_id
   FROM   l
   JOIN   element e USING (category_id, local_id);
$func$  LANGUAGE sql STABLE;

Recupera tutti gli element_id per gli stessi locali e figli di un dato action_id .

Chiama:

SELECT * FROM f_elem(3);

element_id
-----------
6
7

db<>violino qui
OLD sqlfiddle

Questo dovrebbe essere sostanzialmente già più veloce per diversi motivi. I più ovvi sono:

  • Sostituisci l'SQL puro con il ciclo lento in plpgsql.
  • Restringere l'insieme iniziale della query ricorsiva.
  • Rimuovi IN non necessari e notoriamente lenti costruire.

Sto chiamando con SELECT * FROM ... invece di solo SELECT , anche se la riga ha una sola colonna, per ottenere il nome della colonna di OUT parametro (element_id ) ho dichiarato nell'intestazione della funzione.

Più veloce, ancora

Indici

Un indice su action.action_id è fornito dalla chiave primaria.

Ma potresti aver perso l'indice su local.parent_id . Mentre ci sei, rendilo un indice a più colonne di copertura (Postgres 9.2+) con parent_id come primo elemento e local_id come secondo. Questo dovrebbe aiutare molto se la tabella local è grande. Non tanto o per niente per un tavolino:

CREATE INDEX l_mult_idx ON local(parent_id, local_id);

Come mai? Vedi:

Infine, un indice multicolonna sulla tabella element dovrebbe aiutare un po' di più:

CREATE INDEX e_mult_idx ON element (category_id, local_id, element_id);

La terza colonna element_id è utile solo per renderlo un indice di copertura . Se la tua query recupera più colonne dalla tabella element , potresti voler aggiungere più colonne all'indice o rilasciare element_id . O lo renderà più veloce.

Vista materializzata

Se le tue tabelle ricevono pochi o nessun aggiornamento, una vista materializzata che fornisce l'insieme precalcolato di tutte le coppie (action_id, element_id) condividere la stessa categoria renderebbe questo fulmineo . Crea (action_id, element_id) (in quest'ordine) la chiave primaria.