Коллекции, выборка

  • Автор темы Автор темы Gor
  • Дата начала Дата начала
Убери
Код:
Set doc = coll.GetNthDocument(i)
Это очень экспенсив оперейшн.
 
Много лишнего.
Код:
If Iselement(Listeg(doc.MJ_GRID(0))) = True Then
Forall id In Listeg
If (Listtag(id) = doc.MJ_GRID(0)) And (Cdat(id) < Cdat(doc.CompletedDate(0))) Then
'записываем в наш лист новую дату из дока и стираем элемент с текущим листтагом												
Listeg(doc.MJ_GRID(0)) = doc.CompletedDate(0)							
Goto label											
End If
End Forall			
Else
В списке может быть только один элемент с заданным ключем. Выкидываем перебор вместе с Goto.
Т.е.:
Код:
If Iselement(Listeg(doc.MJ_GRID(0))) Then
if Cdat(Listeg(doc.MJ_GRID(0))) < Cdat(doc.CompletedDate(0))) Then Listeg(doc.MJ_GRID(0)) = doc.CompletedDate(0)  
Else
Listeg(doc.MJ_GRID(0)) = doc.CompletedDate(0)
End If

Ну и во втором цикле такая же фигня.
 
Убери
Set doc = coll.GetNthDocument(i)Это очень экспенсив оперейшн.

А почему? Вроде бы отличия особого от
конструкции:

Set doc = coll.GetFirstDocument
While Not doc Is Nothing

Set doc1 = coll.GetNextDocument(doc)
Wend

никогда не замечал...
 
Gor
угу, это одна из фишек уже доказанных даже опытным путем.
так же как GetItemValue будет быстрее прямого обращения
 
В общем, просто выдержка из хелпа, переведешь и догадаешься сам? :)
Для документов из коллекции и вьюхи:
Using getNthDocument to iterate through a loop is strongly discouraged for performance reasons. See GetFirstDocument, GetLastDocument, GetNextDocument, GetNextSibling, GetPrevDocument, and GetPrevSibling for the preferred loop structure.
Using GetNthDocument to iterate through a loop is strongly discouraged for performance reasons. See GetDocument, GetFirstDocument, GetLastDocument, GetNextDocument, and GetPrevDocument for the preferred loop structure.
 
ежели поиск по критерию даёт немного резалтов и не требует шаблона (т.е. ищем "жёсткое" значение), надо пользовать дайжест серч:

эссэсвено, базу подготовить и доки при сохранении тоже
 
Вроде решаеца за один проход по коллекции.
Поля: id - ключ, date - та самая дата...
Код:
Function getCollection As NotesDocumentCollection
On Error Goto errhandle
Dim session As New NotesSession
Dim db As NotesDatabase
Dim searchFormula As String
' типа готовимся
Set db = session.CurrentDatabase
searchFormula = {Form = "MotivatedJudgementForm" & (Status= "Completed")}
' получаем коллекцию
Dim collection As NotesDocumentCollection
Set collection = db.search( searchFormula , Nothing , 0 )
' обработка коллекции - просица в отдельный метод
Dim resultList List As NotesDocument
Dim doc As NotesDocument
Set doc = collection.getFirstDocument
While Not doc Is Nothing
Dim existDoc As NotesDocument
Dim key As String
key = doc.ID(0)
On Error Resume Next
Set existDoc = resultList( key )
On Error Goto errhandle
' блок if then else тоже можно вынести в отдельный метод - будет лучше читацо
If existDoc Is Nothing Then
Set resultList( key ) = doc
Else
If existDoc.Date(0) < doc.Date(0) Then Set resultList( key ) = doc	
End If
Set doc = collection.getNextDocument(doc)
Wend
' создание коллекции на основе списка. опять же - отдельная песня, не относящаяся к логике функции
Dim resultCollection As NotesDocumentCollection 
Set resultCollection = db.Search( "" , Nothing, 0 ) ' создаем пустую коолекцию
Forall result In resultList ' здесь проход по документам в памяти. совершенно не затратно...
Call resultCollection.AddDocument( result )
End Forall
Set getCollection = resultCollection
Exit Function
errhandle:
' пацаны обычно здесь вставляют обработчег - но мы обойдемся....
' Call errHandler.catch( LIB_NAME & "." & Getthreadinfo(1) & ": " & Erl )
Exit Function
End Function

так же как GetItemValue будет быстрее прямого обращения
Сорри. Больная тема. Был у мну как-то начальник - упертый идиот...
Какой нафиг быстрее?? Цифры в студию! Все компилируеца в один исполняемый код. Уже писал здесь. И ссылки приводил. Расширенный синтаксис - маст хэв. Если не умеешь его готовить - не пользуй, но другим не мешай и ерунды не пиши.
 
Не хочу продолжать очередной холивар, но операция получения значения айтема очень быстрая, и как правило, даже в сложном коде по времени занимает от силы пару-тройку процентов от общего времени исполнения.

Гораздо важнее оптимизировать алгоритм, чтобы не было лишних серчей, или получение вью в цикле и т.п.
 
turumbay
Твой алгоритм очень сильно жрет память. Проходили уже. :)
У меня на 5000 документах съел около 300Мб.

Я просто перенес документы из коллекции в список.
 
Вообще, листы объектов
Код:
Dim resultList List As NotesDocument (as NotesDatabase и т.д.)
могут при большом кол-ве этих самых объектов привести к оверфлову стека.
 
Вообще, листы объектов
Код:
Dim resultList List As NotesDocument (as NotesDatabase и т.д.)
могут при большом кол-ве этих самых объектов привести к оверфлову стека.

Игрался с этими списками когда-то, если не ошибаюсь до 20 000 документов было в списке, никакого офервлоу не наблюдал.
 
Согласен, что там довольно большое кол-во должно быть.

List у нас Limited by available memory.
Скоре всего, эта ошибка вылетает, когда мы уже достигли этого самого limit'а.
При использовании list'a string'ов этот самый limit достичь многократно труднее, нежели при использовании list'a объектов.

Я лично 2 раза сталкивался, когда list NotesDocument'ов скукоживался из-за кол-ва элементов.
 
Какой нафиг быстрее?? Цифры в студию!
хочеш цифры есть поиск, обсуждалось сотни раз и эксперементально показывалось.
в остальном - тон попроще, Ваше наболевшее - это лично и только Ваше наболевшее.
 
300 метров наводят на дополнительные размышления. поправьте, если не прав:
основное время выполнения тратится на проход по коллекции.
В варианте со списком документов таких проходов будет только 2: по результатам поиска и в вызывающей процедуре по возвращенной коллекции. В остальных вариантах - проходов будет минимум 3.

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

Если размер коллекции непредсказуем и нет уверенности что она влезет в список - тогда оптимальным по скорости будет вариант со списком юнидов. Тогда кол-во проходов опять же снижается до двух - один в нашей процедуре, один в вызывающей.
Если есть подозрение, что и этот список не влезет в память - можно применять тяжелую артиллерию - выгружать его на диск по мере заполнения :-)
В любом случае, разумно изменить архитектуру так, чтобы не возвращать коллекцию.
 
Автор уже привел решение. Два прохода по коллекции. Память практически не расходуется.
 
хочеш цифры есть поиск, обсуждалось сотни раз и эксперементально показывалось.
в остальном - тон попроще, Ваше наболевшее - это лично и только Ваше наболевшее.
таки холивар.
Ничего нигде не доказывалось, ибо это чушь. Роджерса я уже цитировал... Однако есть еще боле авторитетный пассажир - Andre Guirard. Втыкать здесь: . Not really enough difference to get excited about.
Нет никакого изменения производительности. Все в пределах погрешности измерений. Есть известные проблемы пользования расширенного синтаксиса, но производительность - не в их числе. Если кто-то приведет пример реального, не высосанного из пальца кода, в котором отказ от дот нотации реально увеличил производительность - с меня ящик пива.
icq: 248918412, мыло под ником
З.Ы. Вы умножение на целое число сложением всегда заменяете? Тоже нереально повышает максималку.
З.Ы.Ы. За тон приношу извинения. Я и начал эту возню со слова сорри. Да пребудет с Вами Сила!
модератору - ссылка ценная, остальное можно и потереть...
 
Значит мы вынуждены идти на компромис: либо память, либо скорость.
Если заранее можно оценить размер возвращаемой коллекции, то оптимальным по скорости будет приведенный мной вариант.

В данном случае - лучше потерять в скорости, чем держать открытими тысячи документов.
Во-первых, не факт, что будет быстрее, т.к. система уйдёт в глубокий своп, чтоб держать в памяти столько документов. А дисковая система, как правило, узкое место в производительности серверов.
Во-вторых, у сервера существуют ограничения на общее кол-во открытых хэнлов и пару таких агентов убьют его.
В-третьих, если даже мы оценили, что документов в списке окажется приемлемо небольшое кол-во, агент становится миной замедленного действия. Минимальное увеличение числа пользователей или интенсивности потока документов - и сервер в дауне.
Так что такой код - типичный антипаттерн. Пример того, как делать нельзя.
 
Автор уже привел решение. Два прохода по коллекции. Память практически не расходуется.
Три прохода. Третий - в вызывающей процедуре. А можно - за один.
Самое узкое место здесь - это именно обход коллекции. Если он не в локалке - повышение производительности будет убедительное.
Цифры:
Код:
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim collection As NotesDocumentCollection
Set db = session.CurrentDatabase

Print "Формируем коллекцию"
Set collection = db.AllDocuments

Dim doc As NotesDocument
Set doc = collection.GetFirstDocument
Dim count As Long

Dim newCollection As NotesDocumentCollection
Set newCollection = db.Search( "" , Nothing , 0 )
While Not doc Is Nothing And count < 500
Call newCollection.AddDocument( doc )
count = count + 1
Set doc = collection.GetNextDocument( doc )
Wend

Print "Поехали"
Dim startTic As Long
Dim seconds As Double
startTic = Getthreadinfo(6) 
' Поехали: 3 раза перебрать коллекцию
Call goThroughCollection ( 	newCollection )
seconds = (Getthreadinfo(6) - startTic) / Getthreadinfo(7) 
Print "goThroughCollection Finished. The code ran for " & Format$(seconds, "##0.00") & " seconds." 

startTic = Getthreadinfo(6) 
' Поехали: перебрать коллекцию, создать массив, два раза пройтись по массиву
Call goThroughArray ( 	newCollection )
seconds = (Getthreadinfo(6) - startTic) / Getthreadinfo(7) 
Print "goThroughArray Finished. The code ran for " & Format$(seconds, "##0.00") & " seconds." 
End Sub
Private Function goThroughCollection( i_collection As NotesDocumentCollection )
Dim form As String
Dim i As Long
For i = 0 To 2
Dim doc As NotesDocument
Set doc = i_collection.GetFirstDocument
While Not doc Is Nothing
form = doc.Form(0)
Set doc = i_collection.GetNextDocument( doc )
Wend
Next
End Function
Private Function goThroughArray( i_collection As NotesDocumentCollection )
Dim form As String
Dim docs() As NotesDocument
Dim count As Long
Dim doc As NotesDocument
Set doc = i_collection.GetFirstDocument
While Not doc Is Nothing
Redim Preserve docs( count )
Set docs( count ) = doc
form = doc.Form(0)
count = count + 1
Set doc = i_collection.GetNextDocument( doc )
Wend
Dim i As Long , j As Long
For i = 0 To 1
For j = 0 To count - 1
form = docs( j ).Form(0)
Next
Next
Erase docs
Redim docs(0)
End Function
ping до сервера:
Ответ от x.y.z.z: число байт=32 время=40мс TTL=118
Ответ от x.y.z.z: число байт=32 время=19мс TTL=118
Ответ от x.y.z.z: число байт=32 время=11мс TTL=118
Ответ от x.y.z.z: число байт=32 время=23мс TTL=118
Запуск 1
goThroughCollection Finished. The code ran for 55,94 seconds.
goThroughArray Finished. The code ran for 16,97 seconds.
Запуск 2
goThroughCollection Finished. The code ran for 62,70 seconds.
goThroughArray Finished. The code ran for 17,43 seconds.


В данном случае - лучше потерять в скорости, чем держать открытими тысячи документов.
Во-первых, не факт, что будет быстрее, т.к. система уйдёт в глубокий своп, чтоб держать в памяти столько документов. А дисковая система, как правило, узкое место в производительности серверов.
Во-вторых, у сервера существуют ограничения на общее кол-во открытых хэнлов и пару таких агентов убьют его.
В-третьих, если даже мы оценили, что документов в списке окажется приемлемо небольшое кол-во, агент становится миной замедленного действия. Минимальное увеличение числа пользователей или интенсивности потока документов - и сервер в дауне.
Так что такой код - типичный антипаттерн. Пример того, как делать нельзя.
Все правильно говорите. Все подобные вопросы треба решать с включенной головой.
Мы не знаем задачи, не знаем какое количество документов реально возвращается. Если например ключ - это связка типа месяц-год, фамилия сотрудника и т.п. - он поддается объективной оценке. Конкретное решение выбирается в конкретной ситуации. Как увеличить скорость работы было показано. Все последствия сообщество обсудило. Дальше разработчик решит сам.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab