PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Verbinden Sie zwei Tabellen mit ID und Nachkommen aus einer baumähnlichen Tabelle

Abfrage integrieren

Indem Sie die Logik an mehreren Stellen verbessern, können Sie die gesamte Operation in eine einzige Abfrage integrieren. Das Umschließen in eine SQL-Funktion ist optional:

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;

Ruft alle element_id ab für gleiche und untergeordnete Lokale einer gegebenen action_id .

Aufruf:

SELECT * FROM f_elem(3);

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

db<>fiddle hier
ALTER sqlfiddle

Dies sollte wesentlich sein schon aus mehreren Gründen schneller. Die offensichtlichsten sind:

  • Ersetzen Sie reines SQL durch langsame Schleifen in plpgsql.
  • Einschränken Sie den Anfangssatz der rekursiven Abfrage ein.
  • Entfernen Sie unnötiges und notorisch langsames IN konstruieren.

Ich rufe mit SELECT * FROM ... an statt nur SELECT , obwohl die Zeile nur eine einzige Spalte hat, um den Spaltennamen von OUT zu erhalten Parameter (element_id ) habe ich im Funktionsheader deklariert.

Noch schneller

Indizes

Ein Index auf action.action_id wird durch den Primärschlüssel bereitgestellt.

Aber Sie haben vielleicht den Index auf local.parent_id übersehen . Wenn Sie schon dabei sind, machen Sie daraus einen übergreifenden mehrspaltigen Index (Postgres 9.2+) mit parent_id als erstes Element und local_id als zweite. Dies sollte sehr hilfreich sein, wenn die Tabelle local ist groß. Wenig oder gar nicht für einen kleinen Tisch:

CREATE INDEX l_mult_idx ON local(parent_id, local_id);

Wieso den? Siehe:

Schließlich ein mehrspaltiger Index auf Tabelle element sollte weiter helfen:

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

Die dritte Spalte element_id ist nur sinnvoll, um daraus einen deckenden Index zu machen . Wenn Ihre Abfrage mehr Spalten aus der Tabelle element abruft , möchten Sie vielleicht weitere Spalten zum Index hinzufügen oder element_id weglassen . Beides macht es schneller.

Materialisierte Ansicht

Wenn Ihre Tabellen erhalten nur wenige oder keine Aktualisierungen, eine materialisierte Ansicht, die den vorberechneten Satz aller Paare (action_id, element_id) bereitstellt das Teilen derselben Kategorie würde dies blitzschnell machen . Machen Sie (action_id, element_id) (in dieser Reihenfolge) den Primärschlüssel.