Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2010.01.24;
Скачать: [xml.tar.bz2];

Вниз

В порядке обсуждения 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.007 c
2-1259566616
V@silij Iv@novich
2009-11-30 10:36
2010.01.24
Использование QReport


1-1234095719
dreamse
2009-02-08 15:21
2010.01.24
Подскажите, какое событие возникает


2-1259677152
SergP
2009-12-01 17:19
2010.01.24
Запуск консольного приложения из доп. потока


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


2-1259848543
kate158
2009-12-03 16:55
2010.01.24
добавление д-х из excel на пересечении строки и столбца





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский