sql >> Base de Datos >  >> RDS >> PostgreSQL

Une dos tablas usando id y descendientes del árbol como tabla

Integrar consulta

Mejorando la lógica en varios lugares, puede integrar toda la operación en una sola consulta. Envolver en una función SQL es opcional:

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 todos los element_id para los locales iguales y secundarios de un action_id determinado .

Llamar:

SELECT * FROM f_elem(3);

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

db<>fiddle aquí
ANTIGUO sqlfiddle

Esto debería ser sustancialmente más rápido ya por varias razones. Los más obvios son:

  • Sustituya SQL puro por bucle lento en plpgsql.
  • Restringir el conjunto inicial de la consulta recursiva.
  • Eliminar IN innecesario y notoriamente lento construir.

Estoy llamando con SELECT * FROM ... en lugar de simplemente SELECT , aunque la fila tiene solo una columna, para obtener el nombre de columna de OUT parámetro (element_id ) Declaré en el encabezado de la función.

Más rápido, aún

Índices

Un índice en action.action_id es proporcionada por la clave principal.

Pero es posible que te hayas perdido el índice en local.parent_id . Mientras lo hace, conviértalo en un índice de varias columnas de cobertura (Postgres 9.2+) con parent_id como primer elemento y local_id como segundo Esto debería ayudar mucho si la tabla local es grande. No tanto o nada para una mesa pequeña:

CREATE INDEX l_mult_idx ON local(parent_id, local_id);

¿Por qué? Ver:

Finalmente, un índice de varias columnas en la tabla element debería ayudar un poco más:

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

La tercera columna element_id solo es útil para convertirlo en un índice de cobertura . Si su consulta recupera más columnas de la tabla element , es posible que desee agregar más columnas al índice o soltar element_id . Cualquiera de los dos lo hará más rápido.

Vista materializada

Si sus tablas reciben pocas o ninguna actualización, una vista materializada que proporciona el conjunto precalculado de todos los pares (action_id, element_id) compartir la misma categoría haría que esto fuera rápido como un rayo . Hacer (action_id, element_id) (en ese orden) la clave principal.