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

Slut dig til to borde ved hjælp af id og efterkommere fra trælignende bord

Integrer forespørgsel

Forbedring af logikken flere steder, kan du integrere hele operationen i en enkelt forespørgsel. Indpakning i en SQL-funktion er valgfrit:

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;

Henter alle element_id for samme og underordnede lokale af en given action_id .

Ring til:

SELECT * FROM f_elem(3);

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

db<>fiddle her
GAMMEL sqlfiddle

Dette bør være væsentligt hurtigere allerede af flere årsager. De mest oplagte er:

  • Erstat ren SQL med langsom looping i plpgsql.
  • Begræns startsættet for den rekursive forespørgsel.
  • Fjern unødvendige og notorisk langsom IN konstruere.

Jeg ringer med SELECT * FROM ... i stedet for blot SELECT , selvom rækken kun har en enkelt kolonne, for at få kolonnenavnet på OUT parameter (element_id ) Jeg erklærede i funktionshovedet.

Hurtigere, dog

Indeks

Et indeks på action.action_id leveres af den primære nøgle.

Men du er muligvis gået glip af indekset på local.parent_id . Mens du er i gang, skal du gøre det til et dækkende indeks med flere kolonner (Postgres 9.2+) med parent_id som første element og local_id som anden. Dette burde hjælpe meget, hvis tabellen local er stor. Ikke så meget eller slet ikke for et lille bord:

CREATE INDEX l_mult_idx ON local(parent_id, local_id);

Hvorfor? Se:

Endelig et multi-kolonne indeks på tabel element burde hjælpe noget mere:

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

Den tredje kolonne element_id er kun nyttig for at gøre det til et dækkende indeks . Hvis din forespørgsel henter flere kolonner fra tabel element , vil du måske tilføje flere kolonner til indekset eller droppe element_id . Begge vil gøre det hurtigere.

Materialiseret visning

Hvis dine tabeller modtager få eller ingen opdateringer, en materialiseret visning, der giver det forudberegnede sæt af alle par (action_id, element_id) at dele den samme kategori ville gøre dette lynhurtigt . Lav (action_id, element_id) (i nævnte rækkefølge) den primære nøgle.




  1. psycopg2 kan ikke se min PostgreSQL-instans

  2. Node.js:Definition af Postgres-skemaer i Sequelize

  3. Oracle PL/SQL:Loop over triggerkolonner dynamisk

  4. MySQL-kolonnen sat til NOT NULL, men tillader stadig NULL-værdier