PostgreSQL - эффективная рекурсия с агрегацией - PullRequest
1 голос
/ 30 ноября 2011

У меня есть база данных PostgreSQL 9.1, в которой хранится несколько «областей» с границами, и мне нужно определить эффективную границу для области. Некоторые области хранят границу непосредственно (как геометрия PostGIS), тогда как другие состоят из нескольких дочерних областей, которые необходимо объединить вместе.

Для каждого дочернего элемента существует «операция», которая определяет, будет ли он добавлен к предыдущему или вычтен из него или пересекается с ним. Это означает, что порядок также имеет значение, поэтому есть порядковый номер.

У меня есть агрегатная функция, которая решает эту проблему, но проблема в том, что структура является рекурсивной - дочерняя область сама может состоять из дочерних областей.

Упрощенная схема:

CREATE TABLE area
    (id integer NOT NULL
    , border geometry NULL
    );
CREATE TABLE area_part
    (parent_area_id integer NOT NULL
    , sequence integer NOT NULL
    , operation text NOT NULL
    , child_area_id integer NOT NULL
    );

Сигнатура агрегированной функции (она ожидает строки, упорядоченные по sequence):

CREATE AGGREGATE aggregate_geometry(area geometry, operation text)
-- RETURNS geometry

Я создал обычную функцию PL / pgSQL, которая вызывает себя рекурсивно и работает, но медленно, потому что выполняет много подзапросов. Любые идеи о том, как это можно сделать более эффективно?

Я также пытался написать запрос с рекурсивным CTE:

WITH RECURSIVE area_rec AS
(
    SELECT *
    FROM area
    WHERE id = the_if_of_interest

    UNION ALL

    SELECT c.*
    FROM area_rec rec
    JOIN area_part p ON rec.id = p.parent_area_id
    JOIN area c ON p.child_area_id = c.id
)
SELECT *
FROM area_rec

Это хорошо для возврата всех строк, необходимых для данной области, но я не знаю, как затем вставить значения в мою статистическую функцию. Мне нужна какая-то «совокупная рекурсивная функция» здесь!

1 Ответ

2 голосов
/ 24 марта 2013

Вы действительно должны подходить к такого рода проблемам в два этапа. Первый - создать набор данных, через который вы можете агрегировать (рекурсия, CTE), а второй - агрегирование. Мне кажется, что подход к агрегации является оконной функцией. Затем, если вам нужно, вы можете включить это в другой CTE для дальнейшей постобработки. Помните, что CTE могут быть вложены на произвольную глубину, но вам не нужно больше двух уровней для этого. Вы хотите сделать это как можно более простым.

Без функции я не знаю, как будет выглядеть запрос, но этого должно быть достаточно, чтобы начать работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...