Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.01.24;
Скачать: CL | DM;

Вниз

В порядке обсуждения TDBTreeView.   Найти похожие ветки 

 
Jeer ©   (2009-11-19 18:15) [0]

Только ленивый не прикручивал к стандартному TTreeView отображение данных из БД и я не исключение.
Собственно говоря, такой компонент был написан давным-давно и почти все устраивало.
Однако свалилась на голову беда:
- справочники из многих тысяч иерархических записей;
- произвольная СУБД ( да хоть файл-серверная ), но по стд. SQL-92,
никаких тебе серверных процедур и языков в помощь;
- интенсивная работа пользователя со справочниками ( выбор чекбоксами необходимых ветвей на всю их страшную глубину ),
а значит требование высокой скорости отображения и никаких вариантов на постепенное подсос-открытие ветвей.

В общем, практически тупик.
Одна радость - справочники чрезвычайно консервативны и обновление их возможно не в период работы пользователей.
Поскольку ничего путного из опубликованного в Сети не извлек, пришлось идти собственным путем и, вполне возможно, "велосипедным".

В общем, идея свелась к спец.подготовке справочников к линейной схеме их заполнения.

Таблица имеет вид:
ID ( уник. первичный ключ)
PARENT (ссылка на ID для child )
LEVEL ( уровень иерархии текущей записи )
IDX ( индекс записи в treeview ( аналог node.AbsoluteIndex)
NAME ( всякая текстовуха, как обычно )

Поскольку значения в LEVEL, IDX не могут быть совсем уж монстроидальными, то тип полей может быть
и поменьше, чем integer или longint. По ситуации.

Может показаться, что ID и IDX дублируют др.друга, однако это не так.
ID всегда уникален, а IDX может меняться в зависимости от изменения положения записи в дереве.

Итак, что делаем ? Вначале готовим таблицу.
Открываем датасет, тот же TQuery, например путем select * без order или даже с ним.
Считываем стандартно и "медленно", путем сканирования и построения иерархии по Locate ( ID и PARENT )
Получаем в TreeView отображение иерархии, модифицируем ( переставляем, добавляем ) нужные записи, а по окончании
нажимаем волшебную кнопочку "Записать все" и во все записи проставляются абсолютный индекс IDX узла.
Время по вышеуказанной причине не лимитирует.

Итак, таблица готова к ускоренному отображению, но как ?
Переоткрываем датасет с order by IDX - все записи окажутся в линейном порядке по требуемому индексу TreeView (это будет всегда для пользовательских запросов + всякие условия, если надо).
Пропуски значений в IDX при наложении доп.условий не мешают - важен порядок, а он будет сохранен.

Далее, чтобы не напороться на всякие стандартные node := Items[i], поскольку это приведет к замаскированному поиску по TV и лучше от этого не станет,делаем следующий код:

var
pnd,nd: TTreeNode;
pidx,lvl, old_lvl, d, p: integer;
txt: string;
arP: array of pointer;

***

 SetLength(arP, quY.RecordCount); // с большим запасом, т.к. указатель p будет периодически прыгать к началу для истинного дерева
 p:=0; // указатель позиции в стеке
 old_lvl := 0;
 pnd := nil;

 quTV.First;

 dbTV.Items.BeginUpdate;

 while not quTV.Eof do begin
// чтение уровня записи
   lvl := quTV.FieldByName(fFieldLevelId).AsInteger;
// текстовуха или что надо
   txt := quTV.FieldByName(fFieldText).AsString;

   d := lvl - old_lvl;
// если ныряем в глубину
   if d > 0 then begin
     pnd := nd;
     Inc(p);
     arP[p] := Pointer(pnd);
   end;
// если поднимаемся вверх
   if d < 0  then begin
     p := p + d;
     pnd := arP[p];
   end;
// по ситуации добавляем паханов или детей
   if (lvl=0) then
     nd := dbTV.Items.Add(nil, txt)
   else
     nd := dbTV.Items.AddChild(pnd, txt);

   old_lvl := lvl;
   quTV.Next;
 end; // while

dbTV.Items.EndUpdate;

SetLenght(arP,0);

**************

В итоге такой мазохистский подход дает повышение производительности на два порядка, не меньше.
К примеру из реального - было 800 сек на загрузку, стало 8 сек, что вполне удовлетворительно.

P.S.
Не удивлюсь, что переоткрыл велосипед, ну да я велосипедист :)


 
oldman ©   (2009-11-19 18:19) [1]


> Только ленивый не прикручивал к стандартному TTreeView отображение
> данных из БД


Значит, я ленивый.


 
Германн ©   (2009-11-19 18:25) [2]

Я не ленивый, но более нескольких десятков записей и трех уровней иерархии у меня не было никогда :)


 
И. Павел ©   (2009-11-19 18:31) [3]

Как вариант работы с иерархией:
incl                              |name                  
.                                 |начальник
.abc.                            |заместитель начальника 1
.def.                             |заместитель начальника 2
.def.qwe.                      |заместитель второго заместителя


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


 
Омлет ©   (2009-11-19 18:36) [4]

> [0] Jeer ©   (19.11.09 18:15)
> требование высокой скорости отображения

Лучше бы взять VTV:
http://www.soft-gems.net/index.php?option=com_content&task=view&id=12&Itemid=33


 
Jeer ©   (2009-11-20 09:16) [5]


> Германн ©   (19.11.09 18:25) [2]
>
> Я не ленивый, но более нескольких десятков записей и трех
> уровней иерархии у меня не было никогда :)
>


Значит не всех кошек встречал и не всех умеешь готовить :)

В системах OLAP-класса много чудного встречается, приходится выкручиваться.


> Такая база занимает побольше места но ее проще обрабатывать,
>  чем базу со ссылкой на родительский элемент.


Это аналог введения поля LEVEL, причем худший.


> Лучше бы взять VTV:

С творчеством Лишке я знаком, но VTV не DBAware-компонент, а значит проблема отображения реляции на дерево остается.


 
jack128_   (2009-11-20 13:59) [6]

а зачем загружать все элементы дерева сразу?? почему бы просто не грузить только текущий уровень иерархии??


 
4el0vek   (2009-11-20 14:08) [7]


> Омлет ©   (19.11.09 18:36) [4]

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


 
Jeer ©   (2009-11-20 14:55) [8]


> jack128_   (20.11.09 13:59) [6]
>
> а зачем загружать все элементы дерева сразу?? почему бы
> просто не грузить только текущий уровень иерархии??


Это все понятно и в подобающих случаях это используется, но дело в том в этой задаче, пользователь может чекнуть какую-либо ветку целиком, ее не раскрывая, а это потребует прохода ее вниз, чтобы получить id для формирования запроса вида where F in ( x, y, x,...)
Причем он может это делать многократно, гуляя по разным веткам и даже переоткрывая справочник (не рубить же ему голову за это) и это приведет к значительной задержке в его операциях.
Это вообще особенность OLAP-систем - пользователь занят активным изучением данных.

Диапазон используемых СУБД ( одновременно из одного приложения ) весьма широк, также как и диапазон аппаратных платформ.
Есть даже вариант на CD-ROM ( приложение и временной слепок базы ).

Естественно требуется минимальная вариация в производительности выборок.

Список показателей монстроидален в превосходной степени, но такова задачка :)
http://i026.radikal.ru/0911/ec/ee9b991bdcc9.jpg
http://s39.radikal.ru/i083/0911/c3/988164ef79f4.jpg


 
Polevi ©   (2009-11-20 15:10) [9]

>Jeer ©   (20.11.09 14:55) [8]
>ее не раскрывая, а это потребует прохода ее вниз, чтобы получить id для >формирования запроса вида where F in ( x, y, x,...)
зная id узла вовсе не обязательно раскрывать его на клиенте чтобы получить список всех детей


 
Polevi ©   (2009-11-20 15:15) [10]

к тому же where in (1,2,3,..) рано или поздно натолкнется на ограничение максимальной длины sql запроса для используемой СУБД


 
Jeer ©   (2009-11-20 15:20) [11]


> зная id узла вовсе не обязательно раскрывать его на клиенте
> чтобы получить список всех детей


Таково ограничение - бизнес процессы только на клиенте. Серваки отдыхают от процедур. :)

>натолкнется на ограничение максимальной длины
Ну не надо понимать все буквально - есть еще всякие маленькие хитрости, снижающие такие риски.
Схема БД - это "снежинка", а не "звезда".


 
ANB   (2009-11-20 15:48) [12]


> Jeer ©   (20.11.09 15:20) [11]

Сколько извращений - аж жуть. :)
Отображение дерева руками писал еще на клиппере.
Всего элементов было мало -несколько тысяч (классификатор товаров небольшого магазина).
Тормозов не было.

В оракле спасает connect by, результат легко отображается в дерево.

Вышепрочитанное еще раз убеждает меня, что лучше оракла СУБД нету :)


 
Jeer ©   (2009-11-20 15:54) [13]


> ANB   (20.11.09 15:48) [12]


К сожалению потребовалась "некоторая" универсальность, за которую приходится платить извращениями, увы. Но работает :)
Серваки ( ORACLE, MS SQL, Firebird, Linter,...) стоят чистые и свободные от шаловливых ручек sql-дизайнеров :)
Кушают исключительно SQL-92, такая вот демократия.


 
ANB   (2009-11-20 17:01) [14]


> Кушают исключительно SQL-92

Вот это - полный изврат. Зачем ставить оракл, если им нельзя пользоваться ?


 
jack128_   (2009-11-20 17:08) [15]


> Вот это - полный изврат. Зачем ставить оракл, если им нельзя
> пользоваться ?

угу, я кста тоже не понимаю. в конце концов кроссБДейзность всегда можно на хранимками скрыть.


 
Jeer ©   (2009-11-23 09:33) [16]


> ANB   (20.11.09 17:01) [14]
>
>
> > Кушают исключительно SQL-92
>
> Вот это - полный изврат. Зачем ставить оракл, если им нельзя
> пользоваться ?


Т.е. без хранимок и триггеров и прочей исключительной для конкретного сервака лабуды это уже и не SQL-сервак ?
Хэх.. Вам бы 64к полной памяти и 8-разрядный процессор и DBase II.



Страницы: 1 вся ветка

Текущий архив: 2010.01.24;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.008 c
4-1227466318
demon
2008-11-23 21:51
2010.01.24
Положение рабочей части окна на экране


15-1258373073
RGV
2009-11-16 15:04
2010.01.24
Мастера подскажите где скачать простой и хороший пакер для exe


8-1202567132
multiflex
2008-02-09 17:25
2010.01.24
"Низкоуровневое" воспроизведение


3-1233671912
Pavel
2009-02-03 17:38
2010.01.24
Компонент SQLStoredProc


3-1233556346
Sergey2
2009-02-02 09:32
2010.01.24
update таблицы в Paradox