sql >> Databasteknik >  >> RDS >> PostgreSQL

Slå samman två tabeller med hjälp av id och ättlingar från trädliknande bord

Integrera fråga

Genom att förbättra logiken på flera ställen kan du integrera hela operationen i en enda fråga. Att slå in i en SQL-funktion är valfritt:

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;

Hämtar alla element_id för samma och underordnade lokalbefolkningen av en given action_id .

Ring:

SELECT * FROM f_elem(3);

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

db<>fiol här
GAMMEL sqlfiddle

Detta bör vara väsentligt snabbare redan av flera anledningar. De mest uppenbara är:

  • Ersätt ren SQL för långsam looping i plpgsql.
  • Begränsa startuppsättningen för den rekursiva frågan.
  • Ta bort onödiga och notoriskt långsamma IN konstruera.

Jag ringer med SELECT * FROM ... istället för bara SELECT , även om raden bara har en enda kolumn, för att få kolumnnamnet för OUT parameter (element_id ) Jag deklarerade i funktionshuvudet.

Snabbare men ändå

Indeks

Ett index på action.action_id tillhandahålls av primärnyckeln.

Men du kanske har missat indexet på local.parent_id . Medan du håller på, gör det till ett täckande index med flera kolumner (Postgres 9.2+) med parent_id som första element och local_id som tvåa. Detta borde hjälpa mycket om tabellen local är stor. Inte så mycket eller inte alls för ett litet bord:

CREATE INDEX l_mult_idx ON local(parent_id, local_id);

Varför? Se:

Slutligen ett flerkolumnindex i tabellen element borde hjälpa lite mer:

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

Den tredje kolumnen element_id är bara användbart för att göra det till ett täckande index . Om din fråga hämtar fler kolumner från tabellen element , kanske du vill lägga till fler kolumner i indexet eller släppa element_id . Båda kommer att göra det snabbare.

Materialiserad vy

Om dina tabeller får få eller inga uppdateringar, en materialiserad vy som ger den förberäknade uppsättningen av alla par (action_id, element_id) att dela samma kategori skulle göra detta blixtsnabbt . Gör (action_id, element_id) (i den ordningen) primärnyckeln.




  1. Oracle:Varför jag inte kan lita på ROWNUM i en borttagningsklausul

  2. LYSSNA/MEDDELA pgconnection går ner java?

  3. Dynamiskt genererad CURSOR i Postgresql

  4. utvalda användare har mer än en distinkt post i mysql