powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / кто как работает с деревьями в ПостгреСе?
27 сообщений из 27, показаны все 2 страниц
кто как работает с деревьями в ПостгреСе?
    #32341815
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте всем.

Поделитесь опытом, кто как работает с деревьями в ПостгреСе?

Возникают задачки такого вида: есть табличка-дерево, скажем tree, с полями id и pid (непосредственный предок). В разных случаях надо считать агрегаты по всем листьям но не только текущего узла, но и на ветке, имеющие подчиненные разного уровня вложенности. Задача решается на PostgreSQL 7.3 (но желательна и совместимость решения с 7.0, которая не поддерживает pgplsql - язык поставил, все "компилится" нормально, но не исполняется).


Просматривал для 7.3. вариант с "индексной" таблицей всех предков:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE TABLE public.t_parents
(
  id int4 NOT NULL,
  pid int4 NOT NULL,
  CONSTRAINT t_parents_pkey PRIMARY KEY (id, pid),
  CONSTRAINT id FOREIGN KEY (id) REFERENCES public.tree (id)
 ON UPDATE CASCADE ON DELETE CASCADE,
  CONSTRAINT pid FOREIGN KEY (pid) REFERENCES public.tree (id)
 ON UPDATE CASCADE ON DELETE CASCADE
);
т.е. удаление устаревших предков происходит каскадно по вторичному ключу CONSTRAINT pid. Для добавления новой ветки достаточно триггера наподобие:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
CREATE OR REPLACE FUNCTION public.tr_t_parents()
  RETURNS trigger AS
'DECLARE
cid INTEGER;
BEGIN
SELECT INTO cid NEW.id ; 
 --DELETE FROM t_parents WHERE t_parents.id = cid ;
INSERT into t_parents (id,pid) 
SELECT t.id, t.pid 
from tree AS t
 LEFT JOIN t_parents AS r ON r.id=t.id AND r.pid=t.pid
 WHERE r.id IS NULL AND t.id =cid ;
INSERT INTO t_parents ( id, pid )
SELECT tp.id, p.pid
FROM t_parents AS tp
 INNER JOIN t_parents AS p ON tp.pid = p.id
 LEFT JOIN t_parents AS r ON r.id=tp.id AND r.pid=p.pid
WHERE r.id IS NULL AND tp.id =cid;
RETURN NEW;
END;'
  LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER tr_addupd_t_parents
  AFTER INSERT OR UPDATE
  ON public.tree
  FOR EACH ROW
  EXECUTE PROCEDURE public.tr_t_parents();

При перемещении ветки нужно дополнительно обновить предков для ее потомков. Это тоже делается одной Sql конструкцией. Вроде бы решение позволяет далее вычислять все агрегаты просто SQL конструкциями (без рекурсий). Но мне показалось что при вставке/удалении большого числа записей в tree (а это требуется при подкачке данных из разных локальных приложений), время выполнения запросов на вставку/удаление сильно возрастает.

Нет ли иных, более быстрых решений для обработки деревьев? В том числе, специфичного для PostgreSQL. И что желательно делать для быстрого ("on line") получения агрегатов по веткам близким к корню? (вести так-же и таблицы агрегатов на триггерах? но это дополнительные расходы при вставке/изменении записей, причем, если не пользоваться "индексной" таблицей предков, возможно и требующее рекурсивных вызовов (тоже просматривал, но там, похоже, затраты времени существенно выше - все рекурсивные вызовы по всем триггерам на обновление оказываются в одной транзакции, а вызываются как отдельные SQL конструкции).
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32344688
Sad Spirit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если надо считать агрегаты по целым веткам, то лучше хранить деревья по модели Nested Sets . Вся ветка тут выбирается одним простым запросом, но для вставки/удаления понадобятся процедуры. Хорошо работает, когда запросов на чтение к дереву намного больше, чем на изменение, иначе мусор быстро накапливается.

Есть ещё подход под названием Nested Intervals , но я его сам пока не пробовал.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32345098
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сенькаю.
Читаю.
Интересная арифметика.
Вопрос в том, насколько она быстра.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32345457
Shweik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообщето около месяца назад у меня возникла
странная проблема с проверкой примеров приведенных в статье
Joe Celko ( перевод ее кстати есть где-то здесь на www.sql.ru)
Проблемы там возникли с псевдонимами таблиц.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32346527
Konrad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Schweik
Не с этим ли примером возникли проблемы?

Код: plaintext
1.
2.
3.
4.
SELECT COUNT(P2.emp) AS indentation, P1.emp
FROM Personnel AS P1, Personnel AS P2
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
GROUP BY P1.emp
ORDER BY P1.emp;


С помощью данного запроса предлагают найти глубину вложения каждой вершины и наглядно вывести все дерево.
Только вот сортировка по полю emp наглядности не даст :)
Тут сортировать нужно по полю lft.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32346618
Sad Spirit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
assa
Интересная арифметика.
Вопрос в том, насколько она быстра


весьма быстра, если дерево редко меняется.

если меняется часто, то по таблице придётся достаточно часто гонять VACUUM и REINDEX.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32348041
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо.
_

0. абыдна, да, что нужно так много переписывать (и вправо и вверх, т.е. к корню("вниз"?), по дереву), при вставке одного, даже вершинного узла. Т.е. приходится писать изменения в реально "независимые" (от вставляемых) данные. В этом смысле дозапись только "индексов" предков (id,pid) во вспомогательную таблицу, как я собирался делать, "дешевле" (в расчете на единичный акт). Хотя вспомогательная структура у меня получается рыхлее и избыточнее. Но цена (по дисковым операциям) единичного акта "правки дерева" в ней ниже. (особливо с учетом того, что большая часть операций - вставка вершин). (свой-то вариант я уже реализовал. вот еще выброшу вершины из построения - станет не таким пугающим по объему).


1. если я правильно понимаю, методу не вредна мелкая рихтовка - вместо left & right (left<right) "дешевле" хранить left & {right-left} ({right-left}>0). Ибо при этом добавление вершины в _другую_ ветку не потребует _перезаписи_ {right-left} в узлах соседних (правых) веток (или для "версионника" это без разницы? - т.к. одно из полей - left переписывается, то и вся запись переписывается все равно?). Для индексного поиска (в селектах) достаточен индекс по left, т.ч. редукция поля right на скорость процедур поиска не повлияет. (к тому же в постгре можно ведь кажется иметь и функциональные индексы)


2. нет ли усе-таки наработок (наметок) именно для простейшего (самого "дешевого") способа хранения - хранения ключа непосредственного предка? и именно в PostgreSQL? (Например с однократным открытием курсора и рекурсивным циклом составления выходного набора предков/потомков. С тем, чтобы потом сворачивать полученный набор с листьями уже в SQL конструкциях. - вроде ж постгрес позволяет?) Или в любом случае это будет более тормозным способом (поиска)? Можно ли это доказать? Есть ли какие-то способы проиндексировать набор, возвращаемый функцией, не прибегая к его записи (в виде таблицы) на диск. Что происходит, когда разные сеансы обращаются к одной и той же функции от одних и тех же переменных? И можно ли иметь общую для различных сеансов "временную" таблицу в памяти? (т.е. умозрительный порядок таков: - при отсутствии [временной таблицы] - создаем ее в памяти (хотя бы типа "Список смежных вершин графа") со всеми необходимыми индексами (там же, в памяти) и начинаем ее править и пользовать всеми сеансами, никогда не записывая (если хватает памяти). А то, что она помре при перезапуске сервера нас не грузит - мы имеем на диске данные для построения - ключи предков (в "нормальной" структуре) Есть ли достаточные средства для реализации такого рода подходов?).
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32349190
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
assa2. нет ли усе-таки наработок (наметок) именно для простейшего (самого "дешевого") способа хранения - хранения ключа непосредственного предка? и именно в PostgreSQL?

Я использую Postgres пропатченный Hier http://gppl.terminal.ru/
Этот патч позволяет делать иерархические запросы в синтаксисе Оракла
Вот вывод узла и всех подузлов
Код: plaintext
1.
2.
3.
4.
 select id
   from tab
  start with =  1111    
 connect by prior id = parent_id

Вот вывод узла и всех родителей
Код: plaintext
1.
2.
3.
4.
 select id
   from tab
  start with =  1111    
 connect by id = prior parent_id
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32349203
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сорри, опечатка.

Код: plaintext
start with =  1111    

следует читать как
Код: plaintext
start with id =  1111    
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32349373
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Anatoly Moskovsky
сенькаю. Видел (я вроде как юзарь, а не админ:).

? Не ответите на несколько вопросов:


1. Как впечатления? (по скорости, ресурсам и т.п.). Что будет если "деревья будут большими"?

2. А "штатными" средствами? (не приходилось сравнивать с каким-нить "штатным" решением?)

3. А не секрет, как оно (патч, т.е.) "унутре" работает? Не разбирались? (или работает настоко клево, шо вопросы и не появляются)? Ведь не заметно, чтобы постоянная какая-то структура типа "спец индекса" дерева создавалась. Просто вызвается некая процедура-расширение SQL. стал быть все происходит только и именно при исполнении (без ускоряющих подпорок). А как оно пользует существующие индексы (и пользует ли, или читает все дерево)?
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32349476
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
assa1. Как впечатления? (по скорости, ресурсам и т.п.). Что будет если "деревья будут большими"?
На больших объемах не проверялось, только до 1000 записей

assa2. А "штатными" средствами? (не приходилось сравнивать с каким-нить "штатным" решением?)
На сайте автора, который я приводил, есть упоминания других способов, но я их не проверял.

assa3. А не секрет, как оно (патч, т.е.) "унутре" работает? Не разбирались? (или работает настоко клево, шо вопросы и не появляются)? Ведь не заметно, чтобы постоянная какая-то структура типа "спец индекса" дерева создавалась. Просто вызвается некая процедура-расширение SQL. стал быть все происходит только и именно при исполнении (без ускоряющих подпорок). А как оно пользует существующие индексы (и пользует ли, или читает все дерево)?
Насколько я понял там используется seq_scan (полное сканирование без индексов) вне зависимости от наличия индексов. Но тут я могу ошибаться - лучше у автора спросить, тем более, что у меня не последняя версия модуля.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32349765
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Anatoly Moskovsky
спасибо за подробный ответ.

__
Поясню свой интерес: есть некая система, построенная по принципу "все есть дерево" - т.е. попросту интерфейс для работы с деревом (не мой, ес-но). Посему записей в ней не просто много, а, честно говоря, все (почти) записи, которые есть - и есть дерево (даже листья - не "листья", а "вершины").

Т.е. дерево: а) большое, б) все время перестраивается (достраивается). При этом еще и возникает искушение представлять "он лайн" интегралы (агрегаты) по веткам (дабы повысить информативность).

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

Т.е., оставаясь в предположении использования стандартных средств сервера (наподобие того, что я уже реализовал), для себя я вижу 3 вопроса:
1. можно ли и как размещать таблицы (только) в памяти? при этом именно таблички, видимые всеми сеансами.
2. как проинициализировать вспомогательную таблицу при ее отсутствии, не вызывая побочных эфектов. (т.е. как работать с таблицами, которых может и не быть физически - покроет ли динамический вызов посредством EXECUTE все потребности при создании использующих такие "виртуальные таблички" объектов - в т.ч. - триггерных функций).
3. Что делать, когда (и если) памяти не хватит для размещения всей вспомогательной структуры. (положим 3*4байт*{число записей}*{глубина вложенности}~100Мбайт - для глубины ~ 10 оценка: {число записей}~10**6 - мне бы хватило, но если учесть, что я хочу разместить _таблицы_ (а не сырые данные), да + индексы, то видимо поделить оценку на 10-очку надо, а это уже 10**5 - пожалуй маловато (если не выбрасывать вершины-листья из вспомогательной структуры //надо было бы убрать листья из иерархии еще на этапе проектирования, имхо//)). Если строить для каждого вызова только "кусочек" структуры - возвращаемся к расчету (например рекурсивному перебору) для каждого сеанса. Никаких выгод от "вседоступности" очевидно не будет. Если писать на диск - стоит ли напрягаться по поводу "виртуальных табличек" сегодня? (единственно что я тогда хочу сделать - это реализовать возможность отключать триггера постройки вспомогательной структуры при массовой вставке/удалении в дереве, с последующим перестроением структуры стандартной процедурой. хорошо бы прокатили триггера на стейтмент, а не на каждую запись, но я пока не знаю, как получить наборы "инсертед" и "делетед" вместо записей "нью" и "олд" (не упирался)).

посему и интересуюсь вопросом 4:
а не занимаюсь ли я изобревством велосипедов? Каковы реальные подходы чисто конкретных пацанов?
(К тому ж - сервак мой пока лежит, проверять-то рекомендации, идейки и опасения (в т.ч. рекомендованный Вами патчик) не на чем.)
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32453787
MaximZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тоже интересовался этой темой. Но пока не нашел золотой средины.
Если идти по "японскому" методу, то проблема с обнослением, потому что если таблица большая и ее приходится всю апдейтить, то это не мало с точки зрения занятости.
По этому пок сделал вариант который дольше работает на чтение. Но думаю что это опрадвано. По карайнем мере больше 1000 записей выбирать за раз мло когда приходится, или ветка короче, или просто нет мысла, потому что на страницу не влезает.
Строка имеет id и pid. Вот по ним чешет функция и строит дерево сообщений. Думаю, что это с точки зрения выборки, самый затратный вариант. Но зато вставка сообщения проходит одной командой insert, то есть не надо блокировать всю таблицу для обновления строк. Потом я больше приверженец надежных связей. В моем случае сбои в структуре дерава весьма маловероятны.
А вот в случае если во время обносления кучи строк происходит сбой или еще что то, то тогда можно потерять почти всю струтуру дерева. правда можно конечно подстраховаться ссылкой дочка-родитель, как у меня, и иногда проверять на целостность все дерево.
Ну в общем на любителя.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32492562
marr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А я попробовала алгоритм Nested-Set Model of Trees (Joe Celko) - (его статьи в переводе ходят по рунету под названием "Деревья в sql" и в этом топике упоминались),
В резулььате пример из статьи проходит хорошо, а наша реальная таблица в таблицу с левым и правым маркером преобразуется криво :(
(postgresql 7.2.4)
Может быть кто-нибудь сможет разъяснить алгоритм перехода от исходной таблицы к таблице с левым и правым маркером узла?
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32493365
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 marr:


Выбираем начальный left=1, к примеру. Назначаем его корневому узлу.
Пусть counter = left;
Процедура
Для всех дочерних узлов по отношению к заданному:
начало цикла
назначаем текущему узлу left = ++counter;
ЕСЛИ у текущего узла нет потомков
ТО назначаем текущему узлу right = ++counter;
ИНАЧЕ рекурсивно выполняем Процедуру , передавая в качестве параметра текущий узел.
назначаем текущему узлу right = ++counter;
конец цикла
Конец процедуры


А еще можно предусмотреть добавление новых узлов на листовых узлах и увеличивать right не на 1, а на нечетное число.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32494228
marr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вопрос - на чем это все писать? те циклы и рекурсии, чтобы использовать в постгресе?
(мне приходилось описывать деревья на алгоритмических языках программирования, но тут ведь вся фишка в том, чтобы не выходить из базы?)
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32494623
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 marr:

На plpgsql, наверно. По-моему, я даже где-то видел в сети набор необходимых процедур.
На мой взгляд, подход с ипользованием nested sets оправдывает себя, если:
1) нет интенсивных операций добавления/перемещения узлов в дереве;
2) требуются запросы с получением полного поддерева, начиная с заданного элемента (тогда left и right оказываются полезны).
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32494681
marr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
не похоже :(
тут, наверное нужен какой-нибудь триггер, который запускался бы при добавлении-удалении чего-нибудь в исходной таблице, причем, наверное, все это в транзакцию завернуть надо с этими добавлениями-удалениями :(

У меня проблема именно в том, что существующая таблица где только в системе не используется :( Так что с ней я ничего существенного поделать не могу :((
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32494987
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 marr:

Если уже есть рабочая таблица, и с ней нужно что-то делать, то может имеет смысл задуматься о другом подходе?
На триггерах делать необязательно. Можно использовать представление, например, или вообще отдельную таблицу. Но пока непонятна задача, все это напоминает гадание на кофейной гуще. %)
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32495153
marr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2Заглянул :
Имеется финансовая система компании, написанная на PHP+postgresql (система старая, но на ней живет предприятие, поэтому обращаться с ней приходится весьма бережно.
В ней есть таблица со статьями расходов-приходов финансового блока.
На основании этой таблицы оформляются приходы-расходы и строятся отчеты.
(другие таблицы, конечно, тоже имеют место :)
Сейчас во всех этих местах порядок статей дан по-разному, причем там, где показаны деревья, они сделаны не средствами postgres-а, а на PHP. (В результате в этих местах все работает весьма медленно.) Сейчас народ захотел единообразия и желает во всех местах интерфейса видеть дерево (или часть дерева) статей. Если я начну ваять дерево на PHP, я его сваяю, но для показа одного какого-нибудь отчета потребуектся бог знает какое количество запросов к базе и тормозить это будет так же, как в тех двух местах, где PHP-ое дерево присутствует. Менять структуру данных нельзя, тк программа писалась давно и там столько входов-выходов, что лишнее лучше не трогать. Отсюда желание получить искомое дерево средствами SQL и работать с ним теми же средствами. Те в случаях изменения в статьях может перестраиваться дополнительная таблица, или вью, а при запросах-показах идти работа с этой доп-таблицей (или вью). Не очень путанно :)?
Исходная таблица такая:
Column | Type | Modifiers
---------+------------------------+-----------
id | integer | --- id статьи
parent | integer | default 0 --- id родительской статьи
name | character varying(255) | --- название
type_id | integer | --- тип (необязательное поле)
Triggers: RI_ConstraintTrigger_1395408 -- для id

Пример выборки из этой статьи: (2 последних поля опускаем - это лирика :)
mar_fin=> SELECT id, parent from variants order by id limit 20;
id | parent
-----+--------
116 | 0
117 | 0
118 | 0
119 | 0
120 | 116
121 | 116
122 | 116
123 | 116
124 | 118
125 | 123
126 | 123
127 | 123
128 | 123
129 | 123
130 | 123
131 | 123
132 | 123
133 | 123
134 | 119
135 | 119
(20 rows)
и т.д. пока до двух с полтиной сотен, причем дальше могут опять встретиться корневой уровень с потомками, или без и на любой ветке могут в процессе жизнедеятельности системы появиться новые потомки.
Юзер должен видеть html-ый код, где будет нечто такое: (просто в тексте, или в поле select) - по полю name с добавлением каких-нибудь зрительных атрибутов уровня (например "-"):
-статья раз
--первый потомок статьи раз
--второй потомок статьи раз
---первый потомок второго потомка статьи раз
--третий потомок статьи раз
-статья два
и тд

Ну, собственно, вот :)
почитала про "деревья в sql" по-русски и по-английски, попробовала прогнать тот пример, что там предложен (работник-босс). Все хорошо. Попробовала со своей таблицей - получила массу повторяющихся индексов. Те, похоже, c ней надо разбираться как-то иначе :(
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32495355
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 marr:
Сначала можно посмотреть здесь , как уже писал Anatoly Moskovsky.

Еще можно оценить такой подход.
Добавляем индекс по parent, если его еще нет.
Пишем процедуру, в которой строим дерево, начиная от заданного элемента вниз на заданное число уровней и из которой возвращаем полученный рекордсет.
В этой процедуре рекурсивно будет вызываться процедура, которая выбирает все узлы с заданным parent.
Пишем представление на основе выборки данных из этой процедуры.
Подвешиваем на это представление правила, которые будут модифицировать исходную таблицу.

Для того, чтобы оценить этот подход, нужно посчитать число строк в таблице (table_cnt), и:
select max(pcount) as max_childcnt, min(pcount) as min_childcnt, count(*) as parent_cnt, sum(t.pcount)/count(*) as childcnt_per_parent from (select parent_id, count(*) as pcount from team group by parent_id) as t;
Количество уровней дерева, к сожалению, просто посчитать не удастся.
Затем считаем childcnt_per_parent/table_cnt * 100, это будет означать, какой процент строк мы будем выбирать внутри таблицы. Для того, чтобы индекс использовался и его использование было эффективным, нужно чтобы этот процент оказался небольшим. Точно сказать трудно, но если этот процент будет меньше 5, то доступ по индексу будет почти наверняка эффективным, если процент больше 30, то почти наверняка неэффективным. Количество уровней дерева (его можно оценить, зная данные в таблице), умноженное на childcnt_per_parent, даст верхнюю оценку размера рекордсета, возвращаемого из процедуры, при условии равномерного распределения дочерних узлов по дереву. Надо учитывать, что рекордсет будет формироваться целиком в памяти и после этого возвращаться из процедуры. Parent_cnt означает число разных значений индекса или кардинальность, кстати, а table_cnt - кардинальность таблицы. Еще можно собрать статистику для таблицы и поэкспериментировать с запросами, использующими индекс на parent и использующими полный просмотр.

Теперь, зная все эти показатели, можно оценить эффективность этого подхода.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32497429
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Упомянутый мною метод получения поддерева внутри процедуры можно забыть.
Это не Firebird. Кому интересно поэкспериментировать с разными методами, вот тестовая таблица и процедуры генерации дерева.

Код: plaintext
1.
2.
3.
4.
5.
6.
dbtest=> create sequence seq_tree_id;
CREATE SEQUENCE
dbtest=> create table tree(id integer NOT NULL DEFAULT nextval('seq_tree_id'), parent_id integer, path varchar( 255 ), 
lvl integer, lft integer, rgt integer, data char( 300 ));
CREATE TABLE
dbtest=>




Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
CREATE OR REPLACE FUNCTION f_random(integer, integer) RETURNS integer AS '
DECLARE
	v_minval ALIAS FOR $1;
	v_maxval ALIAS FOR $2;
BEGIN
    RETURN v_minval + round(random() * (v_maxval - v_minval));
end;
' LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION f_nodeadd(integer, integer, varchar) RETURNS integer AS '
DECLARE
    v_parent ALIAS FOR $1;
    v_lvl ALIAS FOR $2;
    v_path ALIAS FOR $3;
    v_id integer;
BEGIN
    select into v_id nextval(\'seq_tree_id\');
    insert into tree(id, lvl, path, parent_id, data) 
    values(v_id, v_lvl, coalesce(v_path || \'.\', \'\') || to_char(v_id, \'99999999\'), v_parent, \'ccc\'); 
    return v_id;
end;
' LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION f_subtree(integer, integer, integer, integer, varchar, integer) RETURNS integer AS '
%af_src_comm_0
DECLARE
    v_parent ALIAS FOR $1;
    v_lvl ALIAS FOR $2;
    v_mincld ALIAS FOR $3;
    v_maxcld ALIAS FOR $4;
    v_path ALIAS FOR $5;
    v_maxlvl ALIAS FOR $6;
    v_id integer;
    v_currcnt integer :=0;
    v_currpath varchar;
BEGIN
    FOR i IN 1..f_random(v_mincld, v_maxcld) LOOP
   	   v_id := f_nodeadd(v_parent, v_lvl, v_path);
	   v_currcnt := v_currcnt + 1;
           v_currpath := v_path || \'.\' || trim(both \' \' from to_char(v_id, \'99999999\'));
	   IF v_maxlvl >1 THEN
	   	v_currcnt := v_currcnt + 
           f_subtree(v_id, v_lvl+1, v_mincld, v_maxcld, v_currpath, v_maxlvl - f_random(1, 3));
	   END IF;
    END LOOP;
    return v_currcnt;
end;
' LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION f_treecreate(integer, integer, integer) RETURNS integer AS '
%af_src_comm_1
DECLARE
	v_maxlvl ALIAS FOR $1;
	v_mincld ALIAS FOR $2;
	v_maxcld ALIAS FOR $3;
	v_currpath varchar := \'\';
	v_root integer;
	v_currcnt integer := 1;
BEGIN
    -- insert root record
    v_root := f_nodeadd(null, 0, null);
    v_currpath := trim(leading \' .\' from coalesce(v_currpath || \'.\', \'\') 
|| trim(both \' \' from to_char(v_root, \'99999999\')));
    v_currcnt := v_currcnt + f_subtree(v_root, 1, v_mincld, v_maxcld, v_currpath, f_random(2, v_maxlvl));
    RETURN v_currcnt;
end;
' LANGUAGE plpgsql;



Теперь вызвать процедуру создания, главное, с параметрами не переборщить.
Надо было встроить ограничитель, конечно.
После этого добавляем индексы, расставляем левый и правый маркеры, и тестируем.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32511729
kibez
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не поленитесь ... загляните в contrib дитекторию
========================
contrib/ltree module

ltree - is a PostgreSQL contrib module which contains implementation of data
types, indexed access methods and queries for data organized as a tree-like
structures.
This module will works for PostgreSQL version 7.3.
(version for 7.2 version is available from http://www.sai.msu.su/~megera/po
stgres/gist/ltree/ltree-7.2.tar.gz)
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32515582
Wireless
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я написал на один из официальных списков рассылки по поводу
http://gppl.terminal.ru/

Вот что ответил Tom Lane:


Ruslan A Dautkhanov <rusland@scn.ru>; writes:

>> Here's the patch ( http://gppl.terminal.ru/ ), which allow
>> PostgreSQL use queries like
>> connect by id = prior parent_id


Isn't this the same patch that we rejected a year or two back?


>> as described in SQL standard...


AFAIK there is no such syntax in any version of the SQL standard.
The syntax that *is* there in SQL99 uses "WITH" to achieve roughly
the same results, but with much syntactic difference from Oracle.

If you'd like to submit a patch that implements spec-compatible
WITH, I can pass along some preliminary work that Andrew Overholt
did at Red Hat.

regards, tom lane
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32595783
strizh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Народ !
А почему вы не используете для кодов узлов деревьев обычный позиционный код типа
1.
1.1
1.1.1
1.1.2
2.
2.1
2.2
2.3
2.4
2.4.1
2.4.2
2.4.2.1
2.4.2.2
и т.д. вместо кодов родителей-потомков в каждой записи ?
Тогда обработка и интерпретация таблицы такого дерева будут доступны любому ... Даже MS-компонента TreeView будет работать :)
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32627000
Болельщик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
strizhНарод !
А почему вы не используете для кодов узлов деревьев обычный позиционный код типа
1.
1.1
... Даже MS-компонента TreeView будет работать :)

А можно подробней? А то у меня проблема: TreeView не заполняется данными из таблицы вида id, parent, name в Postgree.

P.S. Использую делфи и Зеос для доступа к бд. На Mysql такое работает.
...
Рейтинг: 0 / 0
кто как работает с деревьями в ПостгреСе?
    #32634585
strizh2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
>А можно подробней? А то у меня проблема: TreeView не заполняется данными >из таблицы вида id, parent, name в Postgree.

Проблема не в постгресе :), а в обращении к методам компоненты treeview
Я как-то тоже накололся (тоже в Delphi), так шоб побыстрее обойти - использовал стандартный метод заполнения дерева из текстового потока.
...
Рейтинг: 0 / 0
27 сообщений из 27, показаны все 2 страниц
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / кто как работает с деревьями в ПостгреСе?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]