|
|
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Собственно есть необходимость просуммировать некую ветку. Структура таблички стандартная: ИдЗаписи/ИдВладельца/ПолеКотороеНадоСуммировать/ПрочийМусор Вопрос: как это лучше реализовать? Пока я сделал в виде рекурсивной функции. И возникла проблема - при прочих равных расчет одной ветки занимает в 10-15 раз больше времени (примерно 70 против 5 секунд), если в конце функции стоит связка rst.close set rst = nothing Убирать - страшно, мало ли потом аукнется. Не убирать плохо - полторы минуты для того, чтобы пробежать по паре сотен записей... Можно пользоваться dlookupom, не пробовал еще. Но ведь наверняка есть объезженные способы... Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 15:24 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Круто... это что же, частый вызов rst.Close Set rst=Nothing замедляют код в разы ??!!?? Есть над чем задуматься... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 15:34 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Нарисуй код полностью, если это не военная тайна ;-). Скорее всего уходит время на создание Recordset'a ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 15:38 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Совет - измените структуру хранения дерева. Вариантов - масса, они опсаны много где, поищите и обрящите приемлемый для себя вариант. Без этого - только рекурсия. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 15:46 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Если там всего пара сотен записей, то открываешь рекордсет с клиентским курсором, а по нему уже бегаешь. Хоть рекурсивно, хоть в цикле ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 16:02 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Даже без рекурсии, если в цикле пробегаю по записям такой функцией: public function test(id as long) dim rs as recordset set rs = currentdb.openrecordset("table1") rs.findfirst "idrec=" & id test = rs!quantity end function то это происходит в несколько раз быстрее, чем такой public function test(id as long) dim rs as recordset set rs = currentdb.openrecordset("table1") rs.findfirst "idrec=" & id test = rs!quantity rs.close set rs = nothing end function Странно... Я здесь... Я там... Я всегда... Пошел спать. Завтра к обеду думаться будет... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 16:17 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
И ведь самое интересное: за каким я пробегаю в таком цикле по записям?.. Писец. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 16:19 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Можно ещё в каждой записи хранить полный путь до корня, например: Страна/Область/Район/Город/Улица Тогда выбрать ветку будет просто: Код: plaintext Это, конечно, денормализация, но с ней жить легче :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 16:43 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
dllookup работает крайне медленно и лучше его избегать. по возможности рекордсет лучше не создавать и не убивать в цикле а делать это один раз за выполнение кода. я бы попробовал такую методику: создать временную табличку с одним полем и скидывать в нее идентификаторы выбранной ветки до тех пор пока число записей не перестанет увеличиваться (проверять можно не каждый раз) то есть сначала создать табличку с идентификатором начала ветки а затем циклически выполнять запрос вставки. а потом запустить запрос вычисляющий сумму по идентификаторам во временной табличке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2003, 17:45 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Был сильно с устатку, говорил ерунду. Я не суммирую ветку дерева. Есть таблица чертежей. Любой чертеж может быть сборочным - содержать несколько вложенных чертежей. Скажем, чертеж на изготовление двух дверных петель. Каждая петля содержит по два одинаковых "уха" и стержень. Каждое "ухо" состоит из пластины и двух заклепок. Требуется узнать кол-во заклепок. 2 заклепки в "ухе" * 2 "уха" * 2 петли = 8 заклепок. Есть отчет, в котором нужно сосчитать все несделанные детали на тек. момент. Он собирает детали без флажка "закончена" и потом с помощью функции на VBA по указанному алгоритму считает их количество (никаких рекурсий тут нет, это я с другой перепутал). Так вот, rs.close set rs = nothing дает чрезвычайно большую задержку выполнения. :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.09.2003, 12:07 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Табличка присоединенная?\r \r Но в любом случае открывать желательно DB, содержащую таблу, и гонять по ней Seek-ом. В Серверной - ваапще пройтись не в VBA, а курсором. Find - это в источнике-запросе, или в малой табле без индексов.\r \r по поводу rs.close - если открываешь несколько раз за подсчет - просто нехорошо (многократные дисковые операции - тут - чтение), и задержка может быть связана со всякими очистками кеша и повторным чтением (с {.close}, - против исспользования кеша без нее) и т.п.. \r \r Если нет (однократное открытие и закрытие таблы за _все_ время счета) - то очень похоже на вот эту проблему "закрытия" бд , которая, как ни странно, искуственно разрешается "упорядочиванием" (разделением по времени) обращения к различным объектам (даже сыроватый код /для 97/ вполне срабатывает, на порядки быстрее именно в части времени закрытия бд). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.09.2003, 12:31 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
2assa Табличка присоединенная, mdb + mdb. Отрываю рекордсет 1 раз для одной строки запроса, ибо не уверен, что заполнять (опять же из вба) временную табличку будет быстрее, чем открывать/закрывать рекордсет. Про "проблему "закрытия" бд" я помню, тем более, что я с тобой ее и обсуждал :), но она мне не кажется сильно похожей. Рекодсеты-то я открываю все-таки последовательно, а не одновременно. Можно, конечно завести для этого запроса гл. переменную recordset, которую один раз открыть и закрыть "когда-нибудь потом", но это, имхо, очень кривой способ. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.09.2003, 12:44 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
>>Отрываю рекордсет 1 раз для одной строки запроса т.е. ф-я вызывается в запросе, и, в свою очередь, открывает рекордсет? Тогда "задержка" (в т.ч. при явном .close) - из-за затрат на чтение при каждом вызове. Это плёхо. Я так делал исключительно зная, что рекордсет (очень)маленький. //Интересно, что в этом случае, видимо, чтение (повторное) идет из кеша - судя по (малому) времени исполнения запросов с такой ф-ей// т.ч. аккуратненько поюзать глобальный рекордсет и сразу закрыть - не самое последнее дело. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.09.2003, 18:54 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
2assa Ну что ж, попробую... В понедельник поеду к этим товарищам, сделаю и во вторник выложу результаты. Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.09.2003, 21:01 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Вот собственно. Все проверил, количество считается уже после отбора чертежей (думал, м.б. когда писал, недоглядел), а их ок. 1000. И что, действительно открывать гл. переменную-рекордсет? А когда ее чистить? При закрытии отчета? Али сделать запрос каким-нибудь статическим и при форматировании, скажем, области данных?.. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.09.2003, 22:18 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Ойойой! А что значит - слишком сложный запрос?! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.09.2003, 16:11 |
|
||
|
Cуммирование ветки иерархического дерева
|
|||
|---|---|---|---|
|
#18+
Усе. Получилось. Нафик все рекордсеты - сделал по другому. У меня стояло ограничение (зачем сделал - сам не знаю, сейчас вот пригодилось) на количество уровней вложенности. Сейчас сделал такой запросик: SELECT tDrafts.NumDraft, nz([tDrafts].[Quantity],0) AS Quantity1, nz([tDrafts_1].[Quantity],1) AS Quantity2, nz([tDrafts_2].[Quantity],1) AS Quantity3, nz([tDrafts_3].[Quantity],1) AS Quantity4, nz([tDrafts_4].[Quantity],1) AS Quantity5, nz([tDrafts_5].[Quantity],1) AS Quantity6, nz([tDrafts_6].[Quantity],1) AS Quantity7, nz([tDrafts_7].[Quantity],1) AS Quantity8, nz([tDrafts_8].[Quantity],1) AS Quantity9, nz([tDrafts_9].[Quantity],1) AS Quantity10, nz([tDrafts_10].[Quantity],1) AS Quantity11 FROM (((((((((tDrafts LEFT JOIN tDrafts AS tDrafts_1 ON tDrafts.NumHighLevel = tDrafts_1.NumDraft) LEFT JOIN tDrafts AS tDrafts_2 ON tDrafts_1.NumHighLevel = tDrafts_2.NumDraft) LEFT JOIN tDrafts AS tDrafts_3 ON tDrafts_2.NumHighLevel = tDrafts_3.NumDraft) LEFT JOIN tDrafts AS tDrafts_4 ON tDrafts_3.NumHighLevel = tDrafts_4.NumDraft) LEFT JOIN tDrafts AS tDrafts_5 ON tDrafts_4.NumHighLevel = tDrafts_5.NumDraft) LEFT JOIN tDrafts AS tDrafts_6 ON tDrafts_5.NumHighLevel = tDrafts_6.NumDraft) LEFT JOIN tDrafts AS tDrafts_7 ON tDrafts_6.NumHighLevel = tDrafts_7.NumDraft) LEFT JOIN tDrafts AS tDrafts_8 ON tDrafts_7.NumHighLevel = tDrafts_8.NumDraft) LEFT JOIN tDrafts AS tDrafts_9 ON tDrafts_8.NumHighLevel = tDrafts_9.NumDraft) LEFT JOIN tDrafts AS tDrafts_10 ON tDrafts_9.NumHighLevel = tDrafts_10.NumDraft; У них сейчас макс. уровень вложенности - 6-й, поставлю ограничение на 50. 5 раз этот запрос сам с собой связываю, потом перемножаю полученные поля - 3 сек. на 3000 записей (против 5 или 70 на 1000). Нормально. Всем спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.09.2003, 16:27 |
|
||
|
|

start [/forum/topic.php?fid=45&msg=32257863&tid=1679541]: |
0ms |
get settings: |
7ms |
get forum list: |
9ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
44ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
39ms |
get tp. blocked users: |
1ms |
| others: | 186ms |
| total: | 301ms |

| 0 / 0 |
