Форум » [x]Harbour » Ascan ? » Ответить

Ascan ?

Dima: [pre2] Есть массив вида {{},{},{}} поиск веду в первом элементе do while !eof() .. if ascan(klnmas[1],{|fff| fff==nakl_r1->kod_kl})==0 skip loop endif ....... skip enddo медленновато что то или меня уже плющит.... есть какой то другой аналог Ascan который пошустрее работает ? Понятно что вот так быстрее будет if ascan(klnmas[1],nakl_r1->kod_k)==0 skip loop endif RDD скипает быстрее чем работает Ascan с блоком кода.... [/pre2]

Ответов - 44, стр: 1 2 3 All

SergKis: Pasha пишет:Конечно, при использовании хеша добавление в него происходит медленнее, чем при добавлении элемента в массив. Это тоже самое, что добавлять записи в файл с индексом медленнее, чем в файл без индекса, так как в первом случае еще обновляется индекс. Выигрыш достигается затем при поиске по ключу. В bcc использовал вашу функцию AADDU(<aArray>, <xKey>, <nSum1>, [nSum2], ...) при переходе на msvc она не перенеслась, стал использовать Hash (class bkHash, sum method. см. выше), протестировал по скорости в bcc оба способа. Ваш на десятые доли секунды быстрее (тестировал одной на годовой базе). Поэтому очень спокойно перешел на Hash.

Dima: Dima пишет: hb_hEval( hmas, {|key,sval,ind| if(sval[1]==3,aadd(fmas,key),)}) // при размере массива 700000 записей hb_hEval работает 530 мс , хочется что то побыстрее [pre2] dbeval( {|| hmas[recno()]:={kod_kl,nomer}}) ? len(hmas) // 700000 ключей fmas:={} nsec:=seconds() hb_hEval( hmas, {|key,sval,ind| if(sval[1]==5,aadd(fmas,key),)}) ? (seconds()-nsec)*1000 // 594 mc fmas:={} nsec:=seconds() for each v in hmas if v:__enumValue()[1]==5 aadd(fmas,v:__enumKey()) endif next ? (seconds()-nsec)*1000 // 437 mc тут побыстрее будет [/pre2] А еще быстрее можно сделать выборку ? ;)

Pasha: Dima пишет: А еще быстрее можно сделать выборку ? ;) Можно перевернуть хеш. То есть, в качестве ключа использовать kmkod, а вместо значения - массив {{recno(), kod_kl, codn}, ...} Если нужны только номера записей, можно добавлять только recno() примерно так: hmas:={=>} // разверну для ясности dbeval go top while ! eof() hmas[kmcod] := {} AADD(hmas[kmcod], {recno(), kod_kl, codn}) // или AADD(hmas[kmcod], recno()) skip enddo Тогда значением hmas[3] будет массив с номерами записей.


Dima: Pasha Да но KMCOD на разных записях может быть одинаковый , поэтому так не годится. Смысл затеи прост. Из заполненного hash массива быстро выбрать нужные Recno() и сложить в массив. Например нужно выбрать всех клиентов у которых код торгового агента KMCOD равен 5 или скажем выбрать всех клиентов у которых код группы CODGR равен 7. Хотелось сделать универсальный хэш массив (для разного рода выборок для фильтра) и такой массив я как бы создал но поиск по нему оставляет желать лучшего по времени. Хотя результат 500 мс для размера массива 700 000 записей тоже не плох. Имея массив с номерами записей BM фильтр ставится в лет. Сейчас такой массив записей я заполняю иначе (юзаю нужный ордер и заполняю массив). Думалось что с хэш массивом будет быстрее так как не надо лишний раз дергать базу.

Pasha: Dima пишет: Да но KMCOD на разных записях может быть одинаковый , поэтому так не годится. Как раз именно так и годится. Значением hmas[kmcod] будет не один номер записи, а массив recno(). И поиск в этом hmas по значению kmkod будет мгновенным. А одним хеш для всех случаев не обойдешься. Если выборки нужны по нескольким параметрам, то надо и делать несколько хеш-массивов, каждый для своего случая. Смысл использования хеш только в мгновенном поиске. Использовать хеш, чтобы затем делать цикл по нему для поиска бессмыссленно.

Pasha: Дима, если работать с хеш непривычно, я могу выложить свои функции для отсортированных массивов. Мне надо только причесать свой код, тот вариант, что я выкладывал раньше, не сохранился. Суть примерно та же, что и хеш, только выглядит несколько нагляднее. К тому же, как выяснилось, при добавлении в хеш по умолчанию не оптимизировано выделение памяти. А у AADD с этим все в порядке.

Dima: Pasha пишет: Смысл использования хеш только в мгновенном поиске. Использовать хеш, чтобы затем делать цикл по нему для поиска бессмыссленно. Это я уже понял и подумаю над твоей идеей. Спасибо Pasha пишет: Если нужны только номера записей, можно добавлять только recno() Да я это понял. Спасибо. Обдумываю.

Dima: Pasha пишет: К тому же, как выяснилось, при добавлении в хеш по умолчанию не оптимизировано выделение памяти я пока делаю так hb_hAllocate( hms, Lastrec() ) и все нормально по скорости добавления. Pasha пишет: Дима, если работать с хеш непривычно, я могу выложить свои функции для отсортированных массивов. Мне надо только причесать свой код, тот вариант, что я выкладывал раньше, не сохранился. Было бы не плохо и это сильно и не горит , хочу еще сам поиграться с хеш массивами.

SergKis: Pasha пишет:тот вариант, что я выкладывал раньше, не сохранился. Это, наверно, они. http://zalil.ru/34366220

Dima: Pasha пишет: тот вариант, что я выкладывал раньше, не сохранился. да он где то есть на форуме я не давно натыкался на эту тему , нужно пошукать немного.

SergKis: Pasha пишет:А одним хеш для всех случаев не обойдешься. Если выборки нужны по нескольким параметрам, то надо и делать несколько хеш-массивов, каждый для своего случая. Как это будет выглядеть применительно к Leto ? "несколько хеш-массивов" надо пополнять или создавать заново ? С предложенным способом от Dima понятно, при загрузке программы создал такой hash и работаю, на клиенте относительно него, пополняя его при LastRec > len(hmas) до потери пульса.

Dima: SergKis пишет: пополняя его при LastRec > len(hmas) до потери пульса И меня та же идея посещала , но LETO пока не юзаю (поигрался малость - ПОНРАВИЛОСЬ) и перевожу прогу с Clipper на Harbour CDX а потом будет и LETO и вопросов будет видимо много. Ты еще не забывай что такой массив еще нужно корректировать и иметь реакцию на удаление записей с учетом что все это может происходить в сети ;) Вообще при таком подходе либо держать нужно кучку hash массивов и юзать BM фильтра или иметь такую же кучку дополнительных индексов (тегов) и юзать SCOPE. И там и там есть свои и плюсы и минусы , в прочем это смотря какая задача и как все там организовано. На вкус и цвет как говорится , товарищей нет SergKis пишет: пополняя его при LastRec > len(hmas) до потери пульса Как славно что не нужно делать вот такой проверки , да и хэш массивов нет в clipper;) [pre2] if len(hmas)<4096 else endif [/pre2]

SergKis: Dima пишет:Вообще при таком подходе либо держать нужно кучку hash массивов Проще работать с dbf MemIO или даже локальным dbf с полями, обеспечивающими быстрый доступ для создания нужных tag-ов и для переключения просмотров browse. С таблицей сервера relation по recno. Для обеспечения секретности можно поля обезличить (типа R_1,R_2,...) или что-то еще. Сейчас через MemIO примерно так делаем, только не весь dbf, а через запросы. Тоже пока без сервера- процесс перевода с Clipper на cdx в разгаре, потом Leto. Dima пишет:Ты еще не забывай что такой массив еще нужно корректировать и иметь реакцию на удаление записей с учетом что все это может происходить в сети ;) В локальном dbf все записи, с учетом удаленных и только ключевые, не изменяемые поля. На сервере можно включит триггер, заполняющий поле типа TimeStamp (или символьное DtoS(Date())+StrTran(Time(), ":", "")+right(hb_ntos(bk_MilliSeconds()), 3)), для запросов по изменениям ...

Pasha: SergKis пишет: Как это будет выглядеть применительно к Leto ? Если использовать Leto, то надо возложить функцию формирования bm-фильтра на сервер. Зачем гонять данные с сервера на клиент, формировать на клиенте массив с номерами записей и затем гнать обратно этот массив на сервер ? Зачем тогда такой сервер нужен ? Сейчас в BMDBF* по set filter массив с номерами записей и так формируется, но это делается без учета scope. Можно исправить этот недостаток. Я вижу 3 пути для этого: 1) Убедить харбор-сообщество сделать это прямо в харборе (пока не получилось). 2) Скопировать сырцы BMDBF* в letodb и внести в них нужные изменения. 3) Сделать в letodb rdd - наследника BMDBF* и переписать в нем метод SetFilter (это сложнее). Ну и наконец, можно на сервере просто добавить функцию, которой вы передавались параметры: имя тэга, scope, filter, и эта функция сама бы формировала bm-фильтр по этим данным

Dima: Pasha Поддерживаю вариант 2 и "можно на сервере просто добавить функцию"

SergKis: Dima пишет:Поддерживаю вариант 2 и "можно на сервере просто добавить функцию" Тоже

SergKis: Pasha пишет:Ну и наконец, можно на сервере просто добавить функцию, которой вы передавались параметры: имя тэга, scope, filter, и эта функция сама бы формировала bm-фильтр по этим данным Можно было бы обойтись этим, но тогда If rddname() == 'LETO' leto_setBmFilter(Tag,Scopr,Filter) Else dbSetFilter(...) Endif тоже как то ...

Pasha: Добавил на сервере letodb функцию LBM_DbSetFilter Вызов функции с клиента: leto_ParseRec( leto_Udf('LBM_DbSetFilter', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) ) Функция устанавливает bitmap-фильтр по условиям scope, filter, и возвращает буфер с первой записью, удовлетворяющей условию фильтра

Dima: Pasha пишет: LBM_DbSetFilter проясни плиз. если активным является ордер 2 , но в LBM_DbSetFilter я указал xOrder равным 5 , какой ордер будет активным после установки LBM_DbSetFilter ? Должен быть 2 , что то не увидел я в сырцах возврата на прежний индекс после установки LBM_DbSetFilter. Сейчас я ставлю простой фильтр когда SCOPETOP и SCOPEBOTTOM равны вот так. Прежний ордер остается на месте в любом случае после выполнения XbmFilter. [pre2] func XbmFilter(nseaord,xsea,myblock) local ret:=.t. local old_ord:=indexord() local old_rec:=recno() local afilt:={} default myblock to nil dbclearfilter() dbsetorder(nseaord) if dbseek(xsea) dbOrderInfo(DBOI_SCOPEBOTTOM,,, xsea) dbeval({|| aadd(afilt,recno())},myblock,,,,.t.) dbOrderInfo(DBOI_SCOPEBOTTOMCLEAR) endif dbsetorder(old_ord) if len(afilt)>0 BM_DBSETFILTERARRAY(afilt) go top else ret:=.f. dbgoto(old_rec) endif return ret [/pre2]

Pasha: На сервере нет информации о том, какой управляющий индекс у клиента. Поэтому в каждой команде, которая поступает с клиента (для которой это конечно необходимо), должен быть прямо указан индекс. Следовательно, серверу нет необходимости возвращать прежний индекс. Поэтому не должно быть такой ситуации, когда управляющий индекс на клиенте один, а LBM_DbSetFilter получает другой. Чтобы избежать этого, я на клиенте добавил функцию, у которой всего 3 параметра: LBM_DbSetFilter( <xScope>, <xScopeBottom>, <cFilter> ) При этом серверу автоматически передается текущий индекс.



полная версия страницы