Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> хранение деревьев в базе, немного оффтов но всеже 
:(
    Опции темы
Ramirez
Дата 30.1.2009, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 18.1.2005
Где: Moscow, ExUSSR

Репутация: 4
Всего: 5



Извиняюсь за небольшой оффтоп, но всетаки спрошу здесь: кто какие способы хранения древовидных структур в реляционных бд знает/использует?

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

кто-нибудь ковырял эту тему?
PM ICQ   Вверх
gcc
Дата 30.1.2009, 19:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



про это видел,
http://gsbelarus.com/gs/modules.php?name=N...cle&sid=314

а связи из вложениями не могут подойти по id с LEFT JOIN и etc? 

PM WWW ICQ Skype GTalk Jabber   Вверх
Aslan74
Дата 30.1.2009, 20:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 23.12.2004

Репутация: нет
Всего: нет



связи ID<->ParentID самое очевидное. Вас интересует способ хранения или загрузки?
PM MAIL WWW ICQ Skype   Вверх
KSURi
Дата 30.1.2009, 21:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 20
Всего: 27



Вопрос скорее в раздел про базы данных


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
gcc
Дата 5.2.2009, 01:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



не совсем понятно как это сделать

вот есть еще модуль DBIx::Tree

если дерево будет так, то как мне вытащить, рекурсию надо как-то написать на perl?

Код

---------
id parent
---------
 3      0
 5      0
 7      0
10      3
11      7
12      5
13      3
16     10
21     16
26     11
30      3
47      7
60     10
73     13
75     47
---------


    
Код


o- 3
|
+-o- 10
| |
| +-o- 16
| | |
| | +-o- 21
| |
| +-o- 60
|
+-o- 13
| |
| +-o- 73
|
+-o- 30

o- 5
|
+-o- 12

o- 7
|
+-o- 11
| |
| +-o- 26
|
+-o- 47
  |
  +-o- 75


Добавлено @ 01:29
Aslan74, и хранения, и загрузки  smile mysql

UPD:

довольно не плохо описано в модуле DBIx::Tree

Это сообщение отредактировал(а) gcc - 5.2.2009, 02:03
PM WWW ICQ Skype GTalk Jabber   Вверх
Ramirez
Дата 5.2.2009, 12:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 18.1.2005
Где: Moscow, ExUSSR

Репутация: 4
Всего: 5



Цитата(Aslan74 @  30.1.2009,  20:42 Найти цитируемый пост)
связи ID<->ParentID самое очевидное. Вас интересует способ хранения или загрузки? 

Вот в том-то и дело, что самое очевидное обычно не самое удобное =(
Вот сколько запросов придется делать чтобы в такой схеме выполнить следующие стандартные операции (рекурсию не рассматриваем):

1. Выбрать дерево целиком (с уровнем каждого элемента)
2. Выбор подчиненных узлов определенного узла
3. Выбор родительской ветки (с уровнями элементов)
4. Выбор ветки в которой участвует заданный узел (с уровнями элементов)

Врядли каждую операцию удасться вписать в один запрос. Несомненный плюс данной схемы - простота добавления/перемещения узлов.


Это сообщение отредактировал(а) Ramirez - 5.2.2009, 12:01
PM ICQ   Вверх
gcc
Дата 5.2.2009, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



в innodb программно как делается, наверное на внешних ключах...

я хотел как раз это сделать на MyISA, мне этот модуль подходит, там еще есть http://search.cpan.org/search?query=DBIx%3...e+&mode=all
PM WWW ICQ Skype GTalk Jabber   Вверх
NuINu
Дата 5.2.2009, 17:05 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 131
Регистрация: 19.7.2008

Репутация: 5
Всего: 6



smile
хотите дам реализацию на Rose?

делаем так: база такая

CREATE TABLE nodes (
    id          INTEGER PRIMARY KEY,
    parent_id   INTEGER,
    name        TEXT
);

это для sqlite

создаем объект My::Node
Код

package My::Node;

use base 'My::DB::Object';

__PACKAGE__->meta->setup
(
      table      => 'nodes',
      #columns    => [ qw(id parent_id name) ],
      columns =>
      [
        id      => { type => 'integer', primary_key => 1, not_null => 1 },
        parent_id => { type => 'integer' },
        name      => { type => 'varchar', length => 255 },
      ],

      pk_columns => 'id',

      relationships =>
      [
        parent =>
        {
             type       => 'many to one',
             class      => 'My::Node',
             column_map => { parent_id => 'id' },
        },
        child =>
        {
             type       => 'one to many',
             class      => 'My::Node',
             column_map => { id => 'parent_id' },
        },

      ],

);


package My::Node::Manager;
use base qw(Rose::DB::Object::Manager);

sub object_class { 'My::Node' }

__PACKAGE__->make_manager_methods('nodes');


1;


заполняем:
Код

#!/usr/bin/perl -w

use strict;
use My::Node;

package main;

#подготовим базу для работы с классом My::Node
my @pr_data = (
{id=>3, name => 'my 3'},
{id=>5, name => 'my 5'},
{id=>7, name => 'my 7'},
{id=>10, parent_id=>3, name => 'my 10'},
{id=>11, parent_id=>7, name => 'my 11'},
{id=>12, parent_id=>5, name => 'my 12'},
{id=>13, parent_id=>3, name => 'my 13'},
{id=>16, parent_id=>10, name => 'my 16'},
{id=>21, parent_id=>16, name => 'my 21'},
{id=>26, parent_id=>11, name => 'my 26'},
{id=>30, parent_id=>3, name => 'my 30'},
{id=>47, parent_id=>7, name => 'my 47'},
{id=>60, parent_id=>10,name => 'my 60'},
{id=>73, parent_id=>13, name => 'my 73'},
{id=>75, parent_id=>47, name => 'my 75'}
);  


foreach my $p_d (@pr_data) {
    my $p = My::Node->new(%$p_d);
    $p->save;
    print_node($p);
}

print "Exit\n";

sub print_node {
    my $node = shift;
    print "id: $node->{id}, p_id: $node->{parent_id}, N: $node->{name}\n"
}



получаем выбоку из "леса"
Код

#!/usr/bin/perl -w

use strict;
use Data::Dumper;
#unshift (@INC, ".");
use My::Node;


package main;

#Теперь обработаем всю базу, начнем с узлов не имющих предков!!!

my %query =
(
      parent_id  => undef
);

my @q = (%query);
my $rez = My::Node::Manager->get_nodes(
    query   => \@q,
    multi_many_ok   => 1,
);


foreach my $cur (@$rez) {
    print "Tree: $cur->{id}\n";
    print_node($cur);
    node_child_walk($cur->{id});
    print "\n";
}
print "Exit\n";

sub node_child_walk {
    my $cur_id = shift;
    my $lev    = shift || 0;
    $lev++;
    
    my %query =
    (
      parent_id  => $cur_id
    );

    my @q = (%query);
    my $rez = My::Node::Manager->get_nodes(
    query   => \@q,
    with_objects => [ 'child' ],
    multi_many_ok   => 1,
    );

    foreach my $p (@$rez) {
    print "\t"x($lev);
    print_node($p); 
        #дальше ищем узлы у которых текущий является родителем
    if($p->child) {
        $lev++;
        foreach my $c (@{$p->child}) {
        print "\t"x$lev;
        print_node($c); #распечатка теперь будет в низлежащей функции
        node_child_walk($c->{id}, $lev);
        }
        $lev--;
    }
    }
}


sub print_node {
    my $node = shift;
    my $id   = $node->{id} || '0';
    my $p_id = $node->{parent_id} || '0';
    my $name = $node->{name} || 'unknown';
    print "id: $id, p_id: $p_id, N: $name\n"
}


ну и наблюдаем результ:
Код

$ ./get_child_nodes_04.pl
Tree: 3
id: 3, p_id: 0, N: my 3
        id: 10, p_id: 3, N: my 10
                id: 16, p_id: 10, N: my 16
                        id: 21, p_id: 16, N: my 21
                id: 60, p_id: 10, N: my 60
        id: 13, p_id: 3, N: my 13
                id: 73, p_id: 13, N: my 73
        id: 30, p_id: 3, N: my 30

Tree: 5
id: 5, p_id: 0, N: my 5
        id: 12, p_id: 5, N: my 12

Tree: 7
id: 7, p_id: 0, N: my 7
        id: 11, p_id: 7, N: my 11
                id: 26, p_id: 11, N: my 26
        id: 47, p_id: 7, N: my 47
                id: 75, p_id: 47, N: my 75

Exit

вот такие дела. smile

Это сообщение отредактировал(а) NuINu - 5.2.2009, 17:17
PM MAIL   Вверх
gcc
  Дата 5.2.2009, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



NuINu, кстате, а ORM делает один запрос или несколько маленьких? ну если вытаскивать много данных на одну страницы с разных таблиц?
PM WWW ICQ Skype GTalk Jabber   Вверх
NuINu
Дата 5.2.2009, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 131
Регистрация: 19.7.2008

Репутация: 5
Всего: 6



по разному
хочешь посмотреть добавь:

package main;
$Rose:smileB::Object::QueryBuilder::Debug = 1;


PM MAIL   Вверх
sir_nuf_nuf
Дата 5.2.2009, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



gcc, да несколько она делает.. это только Oracle (ну может еще что то стольже дорогое) умеет делать рекурсивные запросы,
а mysql и postgresql - только за несколько раз


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
Ramirez
Дата 6.2.2009, 10:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 18.1.2005
Где: Moscow, ExUSSR

Репутация: 4
Всего: 5



NuINu, вы предложили все ту-же архитектуру "в лоб" (child <-> parent), просто красиво скрыв реализацию за фреймворком. Но волшебства-то не бывает, например если выбирать ветку дерева БД все равно придется выполнить несколько запросов (на каждый уровень по запросу). Это физическое ограничение выбранной архитектуры данных. Этим конечно можно пренебрегать пока данных не много. А если уровень вложенности 100 или 1000 уровней а количество записей миллионы? И таких проблем у архитектур "в лоб" множество. Решить их можно только использовав другую архитектуру, представив данные в БД другим, более оптимальным способом.

Вопрос, был скорее: как оптимальнее переложить древовидную структуру в БД, чтобы с ней было удобно работать. кто нибудь встречал что-то лучше чем Nested Sets?

PM ICQ   Вверх
NuINu
Дата 6.2.2009, 12:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 131
Регистрация: 19.7.2008

Репутация: 5
Всего: 6



Ramirez, насколько я помню вся история баз данных начиналась именно с иерархических структур.
т.е ранее все бд специально предназначались для хранения деревьев.


Цитата(Ramirez @  6.2.2009,  08:52 Найти цитируемый пост)
Вопрос, был скорее: как оптимальнее переложить древовидную структуру в БД, чтобы с ней было удобно работать. кто нибудь встречал что-то лучше чем Nested Sets?


на мой взгляд оптимального в принципе не существует. есть оптимальное по отношению к какой то задаче, или набору операций, которые вы хотите производить с данной структурой.
т.е вирт кажеться издал книжку программа = данные + алгоритмы..
а одно без другого не бывает.

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

PM MAIL   Вверх
gcc
Дата 8.2.2009, 23:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



вот еще не мого про DBIx::Tree

http://www.dbpd.com/vault/9810/edb.html
PM WWW ICQ Skype GTalk Jabber   Вверх
gcc
Дата 3.4.2009, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



я вот сделал это дерево для одно сайтика

а как управлять с помошью HTML форм этим деревом? если я захожу переметсить какой-то раздел, то как это сделать красиво (показаст ьродителя и подродителлей),  может с JS как-то? кто делал?
PM WWW ICQ Skype GTalk Jabber   Вверх
myth777
Дата 3.4.2009, 16:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 110
Регистрация: 30.3.2009

Репутация: -1
Всего: -1



Лучше всего одна таблица с

ParentId 
ID 

Если предпологается   большая выборка из таблицы то для быстрого поиска и пробежке по дочерним нодам лучше создать дополнительную таблицу с сылкой на дочерние ноды и принебречь избыточностью данных. 
PM MAIL   Вверх
Vaneska
Дата 6.4.2009, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 141
Регистрация: 15.3.2005
Где: Москва

Репутация: 3
Всего: 4



Цитата(gcc @  3.4.2009,  13:56 Найти цитируемый пост)
а как управлять с помошью HTML форм этим деревом? если я захожу переметсить какой-то раздел, то как это сделать красиво (показаст ьродителя и подродителлей),  может с JS как-то? кто делал?


Я делал это несколькими способами.
1. Самый простой: в форме деталей раздела поле select, а в нем все разделы.
выбираешь нужный, и сабмитишь

2. аяксовый
есть для jquery плагин. simpletree кажется.
у него есть возможность перемещать узлы дерева мышкой.
выводишь на страницу дерево, перемещаешь узлы куда надо.
И нажимаешь кнопку сохранить структуру дерева.
жаваскрипт пробегает по всему дереву строит список узлов и информацией об id, parentid
и отправляет на сервер. Там это все сохраняется в таблицу.
Вариант очень удобен для сортировки узлов дерева.

3. Тоже что и второй, только данные отправляются по каждому узлу,
который перетащил куда-либо.
Вариант удобен для работы с большими деревьями.

--------------------
http://isokolov.blogspot.com/
PM MAIL ICQ   Вверх
gcc
Дата 3.5.2009, 08:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



подскажите как вывести всех родителей дерева из id и name

есть
Код

 id | parent_id | name


используется MySQL, рекурсии в ней нету,  такой запрос не реально написать

может ORM поможет? или как запрос написать, в гугле не нашел....!
PM WWW ICQ Skype GTalk Jabber   Вверх
sir_nuf_nuf
Дата 3.5.2009, 10:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 14
Всего: 31



gcc, ну вы почитайте топик с самого начала. Все как раз таким вопросом и задаются.
Там даже статья есть.
В MySQL - пока никак.  Т.е. нужно придумывать доп. конструкции в базе
В PostgreSQL - вроде добавили рекурсию в последней версии


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
Vaneska
Дата 5.5.2009, 10:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 141
Регистрация: 15.3.2005
Где: Москва

Репутация: 3
Всего: 4



Цитата(gcc @  3.5.2009,  08:11 Найти цитируемый пост)
подскажите как вывести всех родителей дерева из id и name


1. По каждому найденному родительскому узлу делать sql запрос.
Минусы - много запросов к бд.
Если кол. данных возвращаемых запросом небольшое, то есть большая вероятность, что запросы
будут положены в кеш бд. Соответственно скорость работы будет высокой.

2. Кешировать у себя в программе целиком дерево.
Можно кешировать простым списком, а можно строить полноценное дерево.
На CPAN есть модули работы с деревьями.
Т.к. данные все есть, то выбрать из них нужное не составит проблем.
Способ не очешь хорош на больших деревьях, т.к. приходится все дерево хранить в памяти.
Но зато очень быстрый.

Если Ваше приложение - cgi, то стоит подумать, что выбрать. Если fastcgi и т.п., то однозначно второй способ.
Только надо не забывать при изменении дерева обновлять кеш.

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

И еще. Можно хранить не целиком все данные о дереве, а только id, parent_id, sort. Тогда будет меньше памяти занимать. А недостающие данные можно уже доставать sql запросом.
--------------------
http://isokolov.blogspot.com/
PM MAIL ICQ   Вверх
gcc
Дата 5.5.2009, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 1
Всего: 17



нашел что NestedSet как раз для того чтобы, вытащить часть родителей и не делать рекурсию...

еще нашел вариант, серилизации в отдельном столбце всех id родителей, например: 001.005.009.020.030

Это сообщение отредактировал(а) gcc - 5.5.2009, 11:57
PM WWW ICQ Skype GTalk Jabber   Вверх
Ramirez
Дата 8.5.2009, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 18.1.2005
Где: Moscow, ExUSSR

Репутация: 4
Всего: 5



NestedSet  вообще позволяет делать практические любые операции с деревом без рекурсии и достаточно простыми запросами.
единственный минус - очень ресурсоемкие операции вставки/перемещения узлов.

Это сообщение отредактировал(а) Ramirez - 8.5.2009, 11:20
PM ICQ   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0653 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.