26.09.2004, 14:23 | #61 |
Участник
|
в том то и дело, что нужно будет.
Скорее всего, такую иерархию введет организация, которая занимается строительно-монтажными работами. Причем наверняка эта огранизация занимается разными видами строительно-монтажных работ. Так вот "Для наружных работ", "Для мебели", "Для ремонта" - это виды деятельности. И очень типично, что виды деятельности компании замешиваются куда-то в середину иерархии. По-крайней мере, это очень типично для тех? с кем я работал. Да, есть 5% случаев - это сам производитель лаков и красок Но в остальных 95% случаев виды деятельности будут в середине иерархии. Хоть так, хоть иначе. |
|
26.09.2004, 14:30 | #63 |
Участник
|
Цитата:
Сообщение от mazzy
Цитата:
Сказано. Правда во второй части.
Пример - спецификации (BOM). Узлы состоят из материалов и других узлов. Спецификации - типичная иерархия. Причем именно иерархия, а не граф. С циклами в спецификациях в обязательном порядке приходится бороться. Причем спецификациям изначально присуща рекурсия. Рекурся содержится в определении. Причем именно бесконечная рекурсия. Так что не любую иерархию можно описать несвязанными полями. Просто в БОЛЬШИНСТВЕ случаев иерархию применяют совершенно неоправдано. Еще раз спасибо за высказывания. По большей части - с вами совершенно согласен. Действительно BOM - живейший пример "нормализованных" деревьев в Аксапте - а я про них как то и не вспомнил даже. |
|
26.09.2004, 14:43 | #64 |
Участник
|
Цитата:
Сообщение от mazzy
в том то и дело, что нужно будет.
Скорее всего, такую иерархию введет организация, которая занимается строительно-монтажными работами. Причем наверняка эта огранизация занимается разными видами строительно-монтажных работ. Так вот "Для наружных работ", "Для мебели", "Для ремонта" - это виды деятельности. И очень типично, что виды деятельности компании замешиваются куда-то в середину иерархии. По-крайней мере, это очень типично для тех? с кем я работал. Да, есть 5% случаев - это сам производитель лаков и красок Но в остальных 95% случаев виды деятельности будут в середине иерархии. Хоть так, хоть иначе. Мебель \ ... Бытовая техника \ ... Бытовая химия \ ... и т.д. Да это мне кажется уже неважно - суть вопроса ведь ясна. Для нас "видом деятельности" скорее являются признаки сезонности товара и тому подобного - вот их мы делаем отдельными полями таблицы, не более того. Классификатор старались сделать как можно более "ассортиментным", но не я его делал, да и в то время когда он составлялся я был далёк мыслями от этой темы. Сейчас просматривая наш классификатор я нахожу его процентов на 10-20 ненормализованным. |
|
27.09.2004, 11:19 | #65 |
Участник
|
Ещё одна интересная ссылка по теме
http://www.sql.ru/articles/mssql/010...eesInSQL.shtml |
|
27.09.2004, 12:55 | #66 |
Moderator
|
Спасибо =A=L=X= за развернутый трактат о методике построения деревьев.
Небольшое замечание по поводу ненормализованного лакокрасочного дерева. Идеальный (нормализованный) иерархический классификатор должен содержать набор множеств (корневых) с непересекающимися подмножествами. В случае ненормализованной иерархии возникают пересекающиеся множества, а это уже т.н. R-деревья. Вам это ничего не напоминает? Я имею ввиду геоинформационные системы. А это ведь одни из наиболее сложных и ресурсоемких систем и не только в плане объема информации. Я хочу сказать, что сложность системы должна соответствовать решаемым задачам. Структуру классификатора надо по возможности максимально упрощать. Возможно даже разбить на несколько отдельных деревьев или делать комбинированную форму с грубой фильтрацией поверх древовидного классификатора. |
|
27.09.2004, 15:52 | #67 |
Участник
|
Цитата:
Сообщение от Valery
Ещё одна интересная ссылка по теме
http://www.sql.ru/articles/mssql/010...eesInSQL.shtml Правда прямо не говорится про недостатки (по сравнению с тем же id/parentId подходом): - вставление нового элемента превращается в апдейт в среднем половины записей в базе (против 1 insert-а в случае id/parentId подходе) - алгоритм нахождения непосредственных детей или непосредственного родителя (т.е. только с одного уровня) становится нетривиальной задачей (против 1-ого простого select-а в id/parentId) - алгоритм переноса группы из одного места в другое становится нетривиальной задачей (против 1-ого update-а в id/parentId подходе). выигрыш (правда существенный) имеется только при выборках данных и удалении ветки (где классический подход лажает по полной). Мне на ум приходило некое, компромиссное между этими двумя вариантами, решение - поддерживать избыточную таблицу id / parentId / distance - где хранятся связи между каждым родителем и его детьми, для любого уровня вложенности (distance = 0, если родитель является непостредственным родителем, =1 если через одного и т.д.) В этом случае вставка выполняется за 2 insert-а, выборка всех детей/родителей (как произвольной вложенности, так и до заданного уровня вложенности) - за 1 select, перемещение из группы в группу - нетривиальной задачей, удаление - за 2 delete. Но как ни крути - в рамках реляционных баз деревья - это гимор. По моему при любой организации таких структур всегда какая то из операций над ними будет "нетривиальной". Тут надо исходить из того какие из операций будут выполняться реже других |
|
27.09.2004, 15:54 | #68 |
Участник
|
Цитата:
Сообщение от Dzemon
...а это уже т.н. R-деревья. Вам это ничего не напоминает?..
Я имею ввиду геоинформационные системы.... Я хочу сказать, что сложность системы должна соответствовать решаемым задачам. Структуру классификатора надо по возможности максимально упрощать. Возможно даже разбить на несколько отдельных деревьев или делать комбинированную форму с грубой фильтрацией поверх древовидного классификатора. |
|
27.09.2004, 16:35 | #69 |
Moderator
|
Цитата:
Сообщение от =A=L=X=
Согласен с тем что вы хотите сказать, вот только с R-деревьями (или с таким термином, хотя аналогия с геоинформационными системами мне ничего не сказала) не знаком.
|
|
28.09.2004, 12:22 | #70 |
Участник
|
Цитата:
Сообщение от Valery
Ещё одна интересная ссылка по теме...
http://rdbms.narod.ru/article/tree/index.html Правда, при ссылке на Joe Celko они, по-моему, допустили ошибку. Кстати, одного из авторов предлагаемого подхода знаю лично . |
|
10.10.2004, 23:07 | #71 |
Участник
|
Опубликовал заключительную часть статьи.
Иерархический справочник и Axapta. Часть 3: Проект К сожалению, абсолютно не хватает времени, чтобы оформить результаты так, как хотелось бы. Поэтому выложил статью и проект в настоящем виде. Когда будет время, обязательно вернусь к этой теме. Отдельно и обязательно хотелось бы отметить, что в проекте нет ни строчки кода. Все объекты создавались при помощи drag'n'drop. Используются только возможности ядра. |
|
12.10.2004, 16:52 | #72 |
Участник
|
Возражение против тезиса о том что классификаторы вида id/parentId непомерно тяжеловесны в запросах.
Предположим имеем таблицы: Classif ( id, parentId, level ) // избыточное поле level отнюдь не будет лишним Item ( id, name, ClassifId, ... ) Предполагаемая программа, легко справляющаяся с рекурсией такого классификатора одним запросом должна обладать одним свойством - возможностью делать "динамические запросы". Стараюсь придерживатсья синтаксиса Аксапты, хотя с нарушениями для краткости изложения. Логика универсального запроса, выворачивающего всю структуру таблицы вместе с подчинениями не так уж и сложна на самом деле: Шаг 1: <div class='XPPtop'>X++</div><div class='XPP'>[color=:blue]int[/color] n = ([color=:blue]select[/color] max( level ) [color=:blue]from[/color] Classif).level;</div> Шаг 2: <div class='XPPtop'>X++</div><div class='XPP'> Classif c[ n ]; Item i[ n ]; [color=:blue]select[/color] c[ 1 ] [color=:blue]where[/color] c[ 1 ].ParentId [color=:blue]==[/color] [color=:red]""[/color] [color=:blue]outer[/color] join i[ 1 ] [color=:blue]where[/color] i[ 1 ].ClassifId [color=:blue]==[/color] c[ 1 ].Id [color=:blue]outer[/color] join c[ 2 ] [color=:blue]where[/color] c[ 2 ].ParentId [color=:blue]==[/color] c[ 1 ].Id [color=:blue]outer[/color] join i[ 2 ] [color=:blue]where[/color] i[ 2 ].ClassifId [color=:blue]==[/color] c[ 2 ].Id [color=:blue]outer[/color] join c[ 3 ] [color=:blue]where[/color] c[ 3 ].ParentId [color=:blue]==[/color] c[ 2 ].Id [color=:blue]outer[/color] join i[ 3 ] [color=:blue]where[/color] i[ 3 ].ClassifId [color=:blue]==[/color] c[ 3 ].Id ... [color=:blue]outer[/color] join c[ n ] [color=:blue]where[/color] c[ n ].ParentId [color=:blue]==[/color] c[ n - 1 ].Id [color=:blue]outer[/color] join i[ n ] [color=:blue]where[/color] i[ n ].ClassifId [color=:blue]==[/color] c[ n ].Id</div> Думаю и итоги можно отбирать спокойно подобным образом, сейчас просто нет времени думать над этим. Вопрос теперь в том может ли аксапта быть столь динамичной? Если нет - то можно ведь просто ограничить максимальный уровень вложенности групп классификатора. |
|
12.10.2004, 17:36 | #73 |
Участник
|
Хехе... А ведь таким образом можно выполнять практически любые задачи, связанные с обработкой и траверсированием древовидных структур:
Получение всех родителей текущего элемента дерева: <div class='XPPtop'>X++</div><div class='XPP'>Classif cur; ... [color=:blue]int[/color] n = cur.level; ... Classif parent[ n - 1 ]; [color=:blue]select[/color] parent[ 1 ] [color=:blue]where[/color] parent[ 1 ].Id [color=:blue]==[/color] cur.ParentId join parent[ 2 ] [color=:blue]where[/color] parent[ 2 ].Id [color=:blue]==[/color] parent[ 1 ].ParentId ... join parent[ n - 1 ] [color=:blue]where[/color] parent[ n - 1 ].Id [color=:blue]==[/color] parent[ n - 2 ].ParentId;</div> Получение всех детей текущего элемента получается модификацией фрагмента из поста выше, а именно: <div class='XPPtop'>X++</div><div class='XPP'>[color=:blue]int[/color] n = ([color=:blue]select[/color] max( level ) [color=:blue]from[/color] Classif).level - cur.level; Classif c[ n ]; [color=:blue]select[/color] c[ 1 ] [color=:blue]where[/color] c[ 1 ].ParentId [color=:blue]==[/color] cur.Id [color=:blue]outer[/color] join c[ 2 ] [color=:blue]where[/color] c[ 2 ].ParentId [color=:blue]==[/color] c[ 1 ].Id ... [color=:blue]outer[/color] join c[ n ] [color=:blue]where[/color] c[ n ].ParentId [color=:blue]==[/color] c[ n - 1 ].Id</div> Полная выборка элементов с подэлементами уже описана. Ну и т.д.... |
|
12.10.2004, 21:09 | #74 |
Участник
|
Цитата:
Сообщение от =A=L=X=
Думаю и итоги можно отбирать спокойно подобным образом, сейчас просто нет времени думать над этим.
Вопрос теперь в том может ли аксапта быть столь динамичной? Прежде чем трясти стоит таки немножко подумать, поэкспериментировать... Как по вашему, =A=L=X=, каков план построит SQL для такого запроса? Является ли план оптимальным? Как вы думаете как будет SQL сервер выполнять n внешних соединений? Можно ли ваш запрос сделать таким образом, чтобы он выполнялся оптимально? И только после ответа на эти вопросы можно вернутся к вашему - должна ли Аксапта делать такие запросы Поэкспериментируйте - напишите статические запросы подобного вида. Посмотрите на план... |
|
12.10.2004, 21:41 | #75 |
Administrator
|
Почитал... Интересно...
В целом, Ваша проблема, ИМХО, в том, что Вы ищете какой-то идеальный вариант. Конечно, mazzy здесь народ спровоцировал, назвав свой метод безапелляционно правильным. На самом деле, все зависит от конкретной задачи. В этом отношении мне наиболее ценным из всех статей показался следующий пассаж: Цитата:
Просто постановщики задач, как правило не хотят думать на эту тему, а просто заставляют программистов делать универсальные деревья. Плохим постановщикам так проще жить!
P.S.: Кстати, из всех ссылок наиболее полезной мне кажется ссылка Lexey (http://rsdn.ru/?article/db/Hierarchy.xml). В этой статье действительно дан обзор различных подходов и некоторое (конечно, поверхностное, но для обзора больше и не надо) их сравнение.
__________________
Not registered yet? Register here! Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me |
|
12.10.2004, 21:50 | #76 |
Administrator
|
Что касается "нормализованных" деревьев (вообще-то, этот термин используется для других целей): сомневаюсь, что оно действительно Вам поможет. Что касается технологии: про R-деревья книжки написаны, так что проблемы и подходы к их решению известны. Вы рассматриваете этот вопрос с точки зрения психологии пользователей. Мне кажется, здесь все-таки ситуация тяжелее. И "ненормализованное дерево" может оказаться приемлемым (как вариант, на AxForum'е изначально были разделы Axapta и Navision, в каждом из которых были подразделы Функционал, Программирование и Прочее, но никто не жаловался ). С другой стороны, не факт, что при "нормализации" дерева Вы получите приемлемый для всех пользователей результат.
__________________
Not registered yet? Register here! Have comments, questions, suggestions or anything else regarding our web site? Don't hesitate, send them to me |
|
13.10.2004, 08:11 | #77 |
Участник
|
Цитата:
А это надо?
Прежде чем трясти стоит таки немножко подумать, поэкспериментировать... Как по вашему, =A=L=X=, каков план построит SQL для такого запроса? Является ли план оптимальным? Как вы думаете как будет SQL сервер выполнять n внешних соединений? Можно ли ваш запрос сделать таким образом, чтобы он выполнялся оптимально? select countries outer join cities where cities.countryId == countries.Id outer join streets where streets.cityId == cityId ... (короче говоря ваш пример ) ...особенно, если таблицу Classif проиндексировать по полю level - этим можно будет пользоваться для index hint-а, "разделяющего" города от улиц, а следовательно хороший построитель планов запросов поведет себя почти так же, как в вышеприведенном фрагменте. Конечно выполнятся такой запрос будет несколько медленне чем в случае с разделенными таблицами - как раз затраты на то чтобы отсеивать записи по этому индексу, зато преимущества очевидны - гибкость и универсальность, немыслимая в случае разделенных таблиц, а оно того стоит, когда речь идет о "нормализованном" классификаторе. (Времени проводить сравнительные тесты сейчас просто нет, но тема для меня интересна, возможно когда нибудь займусь этим.) Особенно удобно становится работать с таблицей подобным образом, если ограничивать уровень вложенности справочников (совсем как в 1С) - все накладные расходы очевидны плюс исключается случай, когда из-за одной, очень глубокой ветки запрос на все остальные непомерно раздувается лишними полями в строках, хотя их уровень вложенности мал по сравнению с ней. (Кстати, загоняя поле level в фильтр датасоурсов для такого случая с ограниченной глубиной, мы можем выстраивать такие же формы с "межклассовыми иерархиями" как в вашем примере, почти без единой строчки кода) Цитата:
И только после ответа на эти вопросы можно вернутся к вашему - должна ли Аксапта делать такие запросы
Насчёт вашей последней статьи. Мне собственно непонятно в чём её соль - ведь в ней рассмотрен тривиальный случай межклассовой иерархии отношения один-ко-многим, в коей завязаны 99% всех таблиц в Аксапте и которой в общем то все просто обязаны уметь пользоваться. Отношения между странами-городами-улицами это просто классика жанра реляционных БД. Тут видимо предлагается иерархии упорядочивать таким образом - разбивая их на набор взаимосвязанных таблиц. Действительно многие вещи можно уложить в такую схему (та же ассортиментная классификая товаров вполне может быть разбита на несколько таблиц по уровням классификации). Правда кроме преимуществ простоты подхода недостатков КУЧА: - Жесткая привязка к определенной глубине иерархии - добавление новых уровней превращается в головняки программисту + сопутствующие проблемы - Неоднородность построения запросов, а следовательно неоднородность кода, работающего с универсальным представлением дерева в TreeView - Трудности с привязыванием подчиненных классификатору таблиц к разным его уровням - Невозможность/чрезвычайная затрудненность переноса элементов с уровня на уровень и т.д. (вообще в идеале подход id/ParentId, level может обеспечить приличную универсальность, а если в системе есть возможность строить динамические запросы по вышеобозначенной схеме, то и нормальную производительность, сравнимую с разделением таблиц, особенно при ограниченном уровне вложенности) ... И самое главное - если вы реализовали такой подход и не испытали ни одной из вышеперечисленных трудностей, то значит... вы имеете дело с простыми межклассовыми иерархиями отношений один-ко-многим, так что не морочьте мне голову и не пишите гневных опровержений не по адресу. |
|
13.10.2004, 09:15 | #78 |
Участник
|
Цитата:
Сообщение от =A=L=X=
Если приглядеться чуть чуть то очевидно что предлагаемый запрос почти аналогичен следующему:
select countries outer join cities where cities.countryId == countries.Id outer join streets where streets.cityId == cityId ... (короче говоря ваш пример ) В вашем примере используется одна таблица. Большая. С одним индексом и статистистикой на всех Здесь используется несколько таблиц. С разными индексами. И статистиками. Хотя над вашими словами безусловно стоит подумать. Спасибо. |
|
02.01.2005, 20:52 | #79 |
Участник
|
О реализации дерева в Навижине
http://navisioner.com/html/treeview.htm |
|
10.01.2005, 17:01 | #80 |
Участник
|
Данную серию статей корректней было бы назвать не "Иерархический справочник и Axapta", а "Иерархический справочник не для Axapta".
Создалось впечатление, что Автор подспудно ограничивается иерархиями, построенными по фасетному типу. Поэтому его доводы и выводы скорее относятся не Axapt-е, а к общим вопросам представления данных со структурой подобного рода. В оправдание Автора можно привести тот аргумент, что подобные структуры относительно просты в реализации и понимании и по этой причине чрезвычайно широко распространены. Рассуждения типа "нужно использовать" или "можно использовать" фильтры на таблицы вместо treeview на системах с реляционной структурой конечно интересны. Однако, хотелось бы, что бы Автор, рассмотрел тему с более общих методологических позиций вопросы иерархического представления данных в пользовательских интерфейсах. В этом случае его работа уже не будет восприниматься только как крик души Автора. |
|