Форум » [x]Harbour » DBFNTX: как грамотно прервать работу SET FILTER ? » Ответить

DBFNTX: как грамотно прервать работу SET FILTER ?

Sergy: Добрый день Есть некая таблица: date D8 idx1 N5 idx2 N5 flags C5 string C80 И есть фрагмент программы: [pre2]filter_sx := "" SELE table SET FILT TO IIF(LEN(filter_sx)==0,TRUE,(filter_sx $ table->str)) DBEDIT(...)[/pre2] Т.е. пока в строку фильтра ничего не попало - видны все записи. Если юзер хочет отфильтровать часть записей по содержимому строки - срабатывает фильтр. Возникает ситуация: если таблица большая (>100 тыс записей), расположена на сервере и юзер желает увидеть какие-то "редкие" записи, процесс фильтрации начинает занимать непозволительно долгое время. Юзер понимает, что лучше набрать в фильтре что-то другое, но как остановить процесс текущей фильтрации ? Делал так: [pre2]filter_sx := "" SELE table SET FILT TO MyFilter() DBEDIT(...) ... FUNC MyFilter() IF LEN(filter_sx) == 0 RETURN TRUE ELSEIF INKEY(0) == K_ESC // юзер устал ждать ? filter_sx := "" // выключаем фильтр RETURN TRUE ELSE RETURN (filter_sx $ table->string) ENDIF RETURN TRUE[/pre2] Но данный метод приводит вообще к чудным результатам: в 90% случаев после нажатия Esc - DBEDIT() начинает бешено прокручивать список вверх и зависает на первом элементе таблицы. Насколько понял по отладчику, что-то непонятное (для меня) происходит в недрах объекта в районе :Stabilize() С какой стороны к этому вопросу подступиться? PS: в Clipper было тоже самое - но когда тормозило всё, это было не так заметно, а сейчас, на фоне быстрой и адекватной работы Harbour... напрягает....

Ответов - 120, стр: 1 2 3 4 5 6 All

petr707: Построить временный индекс с индексным выражением , содержащим свою функцию, которая реализует фильтр, бегунок создания и будет отслеживать реакцию юзера. Если индекс построился, подключить его к базе.

petr707: Аналогично - копирование таблицы по FOR-условию, которое содержит фильтр, бегунок (для оценки юзером прогноза завершения) Если копирование прошло без прерывания - переоткрыть обзор на новую таблицу (отфильтрованная часть)

Sergy: Ну так получится, что во всех вариантах время реакции на фильтр окажется наибольшим из возможных: нужно будет пройти всю таблицу и выделить все записи, подходящими по условию. В случае фильтра время реакции зависит от частоты попадания удовлетворяющих записей. Например: в table->string слово "Москва" встречается в каждой десятой записи. А слово "Якутия" - один раз на 2000 записей. В случае фильтра по "Москве" отфильтруется в среднем, 200 записей, чтобы 20 из них попали на экран. А для Якутии придется ждать, пока отфильтруется 40 тысяч записей. В случае FOR-условий и тем более, постройки индекса во всех случаях придется ждать обработки всех >100 тыс. записей...


Pasha: Sergy пишет: FUNC MyFilter() IF LEN(filter_sx) == 0 RETURN TRUE ELSEIF INKEY(0) == K_ESC // юзер устал ждать ? filter_sx := "" // выключаем фильтр RETURN TRUE ELSE RETURN (filter_sx $ table->string) ENDIF RETURN TRUE Inkey(0) надо заменить на Inkey() Ну и SetLastKey(0) перед фильтром не забыть поставить

Sergy: Pasha пишет: Inkey(0) надо заменить на Inkey() Ну да, разумеется. Пример писал по памяти. Общий смысл в том, что если юзер нажимает кнопку Esc - нужно выключить фильтр. Ну и SetLastKey(0) перед фильтром не забыть поставить Да, но к сожалению, это не повлияет на результат. DBEDIT() сходит с ума, если ему сначала функция фильтра выдавала FALSE, а потом на тех-же записях - неожиданно - TRUE...

Dima: Как вариант можно по этому полю сделать индекс а затем с помощью DBOI_SKIPWILD или DBOI_SKIPREGEX выбрать номера записей и все потом загнать в BM фильтр , но боюсь что с NTX он не дружит. Можно пример глянуть в Xharbour skipeval.prg , думаю он и в Harbour будет работать.

Andrey: Sergy пишет: процесс фильтрации начинает занимать непозволительно долгое время В Клипере 5.3 фильтр был оптимизирован, даже по сети у меня поиск летал. При переходе на Харбор пришлось отказаться вообще от SET FILTER - по сетке всегда "тормоза", переделал все эти участки программы на условную индексацию. Sergy пишет: В случае FOR-условий и тем более, постройки индекса во всех случаях придется ждать обработки всех >100 тыс. записей... Если уже есть готовое индексное выражение по одному ключу, то даже на базе 100 тыс. записей условная индексация строится МОМЕНТОМ !

Sergy: Dima пишет: Как вариант можно по этому полю сделать индекс а затем с помощью DBOI_SKIPWILD или DBOI_SKIPREGEX выбрать номера записей и все потом загнать в BM фильтр , но боюсь что с NTX он не дружит. Хм, почитал dbinfo.ch - идея занятная, нужно будет попробовать Andrey пишет: В Клипере 5.3 фильтр был оптимизирован, даже по сети у меня поиск летал. При переходе на Харбор пришлось отказаться вообще от SET FILTER - по сетке всегда "тормоза", переделал все эти участки программы на условную индексацию. Если уже есть готовое индексное выражение по одному ключу, то даже на базе 100 тыс. записей условная индексация строится МОМЕНТОМ ! Не очень понятно, если честно. Вот есть таблица, пример в первом сообщении. В строке длиной 80 символов юзер хочет найти ЛЮБОЕ нужное ему слово. А может быть, часть его. Оно может быть в начале, в середине и в конце строки. Как условная индексация сможет тут помочь ?

Andrey: Sergy пишет: Как условная индексация сможет тут помочь ? Держи индекс по этому полю всегда открытым. SELECT table // открыт файл с первым индексом по полю "string" DBSETORDER(1) Условная индексация тогда будет типа: cSlovo := "моск" cIndexTo := "'это поле индекса по базе для сортировки/ ставь сам любое поле" cFileIndex := "table02.cdx" cFilter := "cSlovo $ table->string .AND. !DELETED()" // можно еще условия поставить, допустим cSlovo1 и т.д. DELETEFILE(cFileIndex) // всегда удаляю индекс (CDX) - так как налетаешь потом на грабли SELECT table DBSETORDER(1) INDEX ON &cIndexTo TO (cFileIndex) FOR &cFilter ORDLISTADD( cFileIndex ) // здесь в раб. область базы добавляется второй индекс DbSetOrder(2) nKolRecords := ORDKEYCOUNT() // кол-во найденых записей TBROWSE() //или DBEDIT() Поставь счетчик времени и увидишь сам быстродействие.

petr707: В строке длиной 80 символов юзер хочет найти ЛЮБОЕ нужное ему слово... Видимо, нужно по-другому организовать хранение данных.. полнотекстовый поиск - это не для NTX, это интернет поисковик какой-то

Andrey: Sergy пишет: Например: в table->string слово "Москва" встречается в каждой десятой записи. А слово "Якутия" - один раз на 2000 записей. petr707 пишет: Видимо, нужно по-другому организовать хранение данных.. Наверно нужно делать просто справочник городов, а в базе хранить коды городов, тогда поиск будет просто "летать" !

Sergy: Andrey пишет: Видимо, нужно по-другому организовать хранение данных.. полнотекстовый поиск - это не для NTX, это интернет поисковик какой-то Andrey пишет: Наверно нужно делать просто справочник городов, а в базе хранить коды городов, тогда поиск будет просто "летать" ! поле table->string C80 содержит описание операции, которое формируется автоматически, но может быть скорректировано юзером. Например: При внутрискладском перемещении товара формируется запись: "цех -> отк" или "отк -> приемка" При продаже товара: "магазин:Иванов (Петров)" При поступлении: "склад << поставщик" и тп. к каждому этому описанию юзер может добавить что угодно, например: "/1=переделать документы", "проверить цены", "уточнить оплату" и тд и тп "Москва" и "Якутия" были абстрактными примерами, поясняющими, что часть этих строк может встречаться чаще и фильтр по ним работает быстро, или "нормально", а если ввести часть других - начинается пипец и юзеру проще срубить задачу через диспетчер. Так что проиндексировать точно не получится и используется полнотекстовый поиск, "как в интернете...". Поэтому ищу способ грамотно выключить фильтрацию "на лету".

Andrey: Sergy пишет: Поэтому ищу способ грамотно выключить фильтрацию "на лету". Пробуй, что я предложил выше.

Sergy: Andrey пишет: Пробуй, что я предложил выше. Andrey пишет: Условная индексация тогда будет типа: cSlovo := "моск" cIndexTo := "'это поле индекса по базе для сортировки/ ставь сам любое поле" cFileIndex := "table02.cdx" cFilter := "cSlovo $ table->string .AND. !DELETED()" // можно еще условия поставить, допустим cSlovo1 и т.д. DELETEFILE(cFileIndex) // всегда удаляю индекс (CDX) - так как налетаешь потом на грабли SELECT table DBSETORDER(1) INDEX ON &cIndexTo TO (cFileIndex) FOR &cFilter Один юзер хочет прямо сейчас найти "Моск", юзер на соседнем компе - "Якут" в тоже самое время. Через минуту первому потребовалось "Санкт-П", а другому - "Казань". Через пару минут дальше - "Иваново". Третий юзер в тоже самое время начал искать "Владивосток". Перестраивать индекс каждый раз? Поставь счетчик времени и увидишь сам быстродействие Понятно, что после создания индекса все "залетает"... Но так ведь его создать сначала нужно, те обработать >100 тыс записей. А это время, причем при всех вариантах - максимально долгое из возможных. Или я что-то не так понял ?

Dima: Sergy пишет: Так что проиндексировать точно не получится и используется полнотекстовый поиск, "как в интернете...". Поэтому ищу способ грамотно выключить фильтрацию "на лету". Забей на такую методу Вот тебе живой пример и тормозов ни каких и все влет пашет. [pre2] #include "dbinfo.ch" REQUEST BMDBFNTX Proc main() FIELD F1 local cPattern local amas:={} RDDSETDEFAULT( "BMDBFNTX" ) aeval(directory("_tst.*"),{|x|ferase(x[1])}) dbCreate("_tst", {{"F1", "C", 20, 0}}) USE _tst while lastrec()<100000 dbappend() F1 := strzero(recno(),10)+chr(recno()%26+asc("A")) enddo INDEX ON F1 TO _tst dbcommit() cPattern:="*101*A" dbgotop() if !eof() .and. ! WildMatch(cPattern, ordkeyval()) dborderinfo(DBOI_SKIPWILD,,,cPattern) endif while !eof() if WildMatch(cPattern, ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPWILD,,,cPattern) enddo // а вот тут в своей проге ты можешь вернуться на нужный тебе индекс BM_DBSETFILTERARRAY(amas) browse() return [/pre2] или можно так и будет еще быстрее [pre2] cRegex:=".*101.*A" cRegex:=HB_REGEXCOMP(cRegex) dbgotop() while !eof() if HB_REGEXHAS(cRegEx,ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPREGEX,,,cRegex) enddo BM_DBSETFILTERARRAY(amas) browse() [/pre2]

Sergy: Dima пишет: REQUEST BMDBFNTX Никогда не сталкивался с таким зверем. Погуглил на этом форуме и в интернете - мало информации. Подтолкните в правильном направлении плиз. Спасибо.

Dima: Sergy Тема есть про BMDBFCDX в твоем случае BMDBFNTX http://clipper.borda.ru/?1-4-0-00000808-000-0-0-1363106357 А вообще harbour\contrib\rddbm\ ЗЫ То есть если умалчиваемым RDD сделать BMDBFNTX то все будет работать как и работало но добавятся новые возможности с BITMAP фильтрами.

Sergy: Dima Спасибо, оказывается, интересная штука! Пошел плотно изучать. Может кому-то будет интересно - вот что надумал. Если нельзя менять SET FILTER "на лету", значит нужно проанализировать - откуда сейчас идет вызов. [pre2] filter_sx := "" SELE table SET FILT TO MyFilter() DBEDIT(...) ... FUNC MyFilter() LOCAL ps:=ProcStack() // получаем стек процедур в виде строки IF LEN(filter_sx) == 0 RETURN TRUE ENDIF IF INKEY() == K_ESC // юзер устал ждать ? IF ("STAB" $ ps) .OR. ("SKIPPED" $ ps) // СЕЙЧАС НЕЛЬЗЯ ! ELSE filter_sx := "" // выключаем RETURN TRUE ENDIF ENDIF RETURN (filter_sx $ table->string) [/pre2] Работает четко - вырубает фильтр без косяков. Параллельно мониторю стек вызовов. Если окажется еще что-то, кроме "STABILIZE", "FORCESTABLE" и "SKIPPED", что приводит к зацикливанию - легко добавить в условие.

Andrey: Dima пишет: То есть если умалчиваемым RDD сделать BMDBFNTX то все будет работать как и работало но добавятся новые возможности с BITMAP фильтрами. Если база открыта рабочей программой RDDCDX, можно ли открывать эту базу с помощью BMDBFCDX только для поиска ? Косяков никаких не будет ? И еще вопрос про поиск для BMDBFCDX: Есть в базе поля FIO1, FIO2, FIO3 .... FIO12 (C 45) Как организовать поиск сразу по всем полям ? SET FILTER тормозит... Да и условие на 12 полей зашкаливает...

Dima: Andrey пишет: Если база открыта рабочей программой RDDCDX, можно ли открывать эту базу с помощью BMDBFCDX только для поиска ? А зачем так поступать. Сразу дефолтным делай BMDBFCDX , все будет работать как и работало + доп возможности с фильтрами. А вообще если шибко надо то да можно открыть ту же базу в новой рабочей области с BMDBFCDX. Потести в общем ;)

Dima: Sergy пишет: ProcStack() Самопал или либа нужна какая ? Вероятно самопал что то типа [pre2] FUNC ProcStack() LOCAL n := 0 Local ret:="" WHILE ! Empty( ProcName( n ) ) ret+=" "+ProcName( n++ ) ENDDO RETURN ret [/pre2]

Andrey: Dima Есть в базе поля FIO1, FIO2, FIO3 .... FIO12 (C 45) А индексы нужно делать тоже сразу по каждому полю ? И как сделать поиск сразу по всем полям за один проход по базе ? Набросай пожалуйста заготовку, как правильно это организовать.

Dima: Заготовку не накидаю а вот идея как бы есть (развивай) Да держим по каждому полю индекс что бы быстро отобрать нужные записи (но это дело вкуса) Переключаемся на первый поисковый индекс и ищем как я выше описывал в примере. Отобрали подходящие записи в массив и установили BM фильтр. Переключаемся на второй поисковый индекс и повторяем процедуру поиска по этому полю собрав подходящие записи в массив. Снимаем BM фильтр (вероятно можно и не снимать) и ставим новый и так далее. Теоретически должно работать быстро. Чем дальше тем меньше записей будет попадать в обработку. Пример [pre2] #include "dbinfo.ch" REQUEST BMDBFNTX Proc main() FIELD F1,F2,F3 local cPattern,cRegex local amas:={} local nsec RDDSETDEFAULT( "BMDBFNTX" ) cls aeval(directory("tst.*"),{|x|ferase(x[1])}) dbCreate("tst", {{"F1", "C", 20, 0},{"F2", "c", 20, 0},{"F3", "c", 20, 0}}) USE tst while lastrec()<100000 dbappend() F1:= strzero(recno(),10)+chr(recno()%26+asc("A")) F2:= strzero(recno(),10)+chr(recno()%26+asc("B")) F3:= strzero(recno(),10)+chr(recno()%26+asc("C")) enddo INDEX ON F1 TO tst1 INDEX ON F2 TO tst2 additive INDEX ON F3 TO tst3 additive nsec:=seconds() cRegex:=".*101.*A" cRegex:=HB_REGEXCOMP(cRegex) dbsetorder(1) dbgotop() while !eof() if HB_REGEXHAS(cRegEx,ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPREGEX,,,cRegex) enddo BM_DBSETFILTERARRAY(amas) amas:={} dbsetorder(2) dbgotop() cRegex:=".*510.*B" cRegex:=HB_REGEXCOMP(cRegex) dbgotop() while !eof() if HB_REGEXHAS(cRegEx,ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPREGEX,,,cRegex) enddo BM_DBSETFILTERARRAY(amas) amas:={} dbsetorder(3) dbgotop() cRegex:=".*510.*C" cRegex:=HB_REGEXCOMP(cRegex) dbgotop() while !eof() if HB_REGEXHAS(cRegEx,ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPREGEX,,,cRegex) enddo BM_DBSETFILTERARRAY(amas) ? seconds()-nsec // 0.16 сек wait browse() return [/pre2] Вот такую функцию можно сделать [pre2] //CrazyFilter({{1,".*101.*A"},{2,".*101.*B"},{3,".*101.*C"}}) Func CrazyFilter(par) local i local amas local cRegex for i=1 to len(par) amas:={} if !empty(par[ i ][2]) cRegex:=par[ i ][2] cRegex:=HB_REGEXCOMP(cRegex) dbsetorder(par[ i ][1]) dbgotop() while !eof() if HB_REGEXHAS(cRegEx,ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPREGEX,,,cRegex) enddo BM_DBSETFILTERARRAY(amas) endif next return nil [/pre2]

nick_mi: Для этого лучше организовать поиск по другому, ИМХО конечно. Заводится дополнительная база из двух полей FIO C(45) NREC N(7) (к примеру, если записей в базе < 9999999 ) в базе индекс по FIO и NREC . Тогда не надо выполнять поиск по всем 12 индексам. Выполнив один поиск по СЛОВУ получаем номера всех записей, у которых встречаются заданное слово в любом из полей FIO1 - FIO12. Если необходимо выполнить поиск по нескольким словам придется, естественно, выполнить пересечение. Усложнится ведение, так как при удалении записи из основной базы необходимо удалить все записи из дополнительной базы, при выполнении PACK перестроить полностью всю базу, но такие процедуры как правило выполняются ночью или в выходные и это по времени не критично. Но поиск будет быстрее. Это-же самое можно применить и для Sergy. Каждре слово из string писать отдельной записью. Естественно, будут ограничения, если есть слово АБВГД поиск можно выполнять по условию АБВ*, но не *БВГ*

Sergy: Dima пишет: Самопал или либа нужна какая ? [pre2] * ---------------------------------------- * FUNC ProcStack(nFrom,nTo,lNeedLines,cDefSep) LOCAL i,res,sx,j DEFAULT nFrom TO 1 DEFAULT nTo TO 40 DEFAULT lNeedLines TO FALSE DEFAULT cDefSep TO ":" res:="" FOR i:=nFrom TO nTo sx:=PROCNAME(i) IF !EMPTY(sx) res += sx IF lNeedLines res += "("+NTRIM(PROCLINE(i))+")" ENDIF IF i < nTo res += cDefSep ENDIF ENDIF NEXT i RETURN res * ---------------------------------------- *[/pre2] Удобно в некоторых случаях делать например так: ProcStack(,,TRUE,CRLF) или просто ProcStack()

ММК: Sergy пишет: Один юзер хочет прямо сейчас найти "Моск", юзер на соседнем компе - "Якут" в тоже самое время. Через минуту первому потребовалось "Санкт-П", а другому - "Казань". Через пару минут дальше - "Иваново". Третий юзер в тоже самое время начал искать "Владивосток". Перестраивать индекс каждый раз? Нет. Меняется временный индекс да и тот у каждого юзера свой ( на локальной машине )

Andrey: ММК пишет: Нет. Меняется временный индекс да и тот у каждого юзера свой ( на локальной машине ) Ага. Я это имел в виду.

Dima: Andrey Так хотел пример (который я дал) и ни чего не ответил в плане BM фильтра.........или не юзал ?

Andrey: Dima пишет: или не юзал ? Спасибо БОЛЬШОЕ. Я его делаю, но там всего много навороченного, так что делаю отдельную версию.

Sergy: ММК пишет: Нет. Меняется временный индекс да и тот у каждого юзера свой ( на локальной машине ) Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно).

Andrey: Sergy пишет: Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно). Поверь, это происходить ОЧЕНЬ быстро. База примерно 50.000 записей, поиск по различным полям базы, включая текстовые поля и мемо-поля. Индексирование происходит за 40-60 сек. сек. Если есть уже открытый индекс по которому нужно выбрать значение, т.е. допустим ФИО и дату (любую) и еще чего нибудь, то 10-20 сек. Эту технологию сделал еще в 1997 г. на Клипере 5.3 и до сих пор использую. Хотя надо бы переходить на LetoDB....

LYSK: Andrey пишет: Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно). когда-то, когда Clipper еще помещался на 720к дискету, существовала такая приблуда, которая называлась SUBINDEX. Это была и автономная программка, и библиотека для S'87 и 5.01.. по памяти где-то так: subindex(исходный-ntx,результирующий-ntx,маска-отбора) т.е. строился индекс на основании другого индекса, даже не обращаясь к записям таблицы. маска например "ИВАНОВ*" я просто для иллюстрации подхода ;-)

alkresin: LYSK пишет: существовала такая приблуда, которая называлась SUBINDEX. Это была одна из фичей Six3. В Harbour это тоже есть, сам, правда, не пробовал.

Pasha: Andrey пишет: Поверь, это происходит ОЧЕНЬ быстро. База примерно 50.000 записей, поиск по различным полям базы, включая текстовые поля и мемо-поля. Индексирование происходит за 40-60 сек. сек. Если есть уже открытый индекс по которому нужно выбрать значение, т.е. допустим ФИО и дату (любую) и еще чего нибудь, то 10-20 сек. Эту технологию сделал еще в 1997 г. на Клипере 5.3 и до сих пор использую. Использование индекса с условием for - это некрасивое решение, поскольку для поиска формируется ненужный разовый индекс, при создании которого идет выборка всего файла. Другое дело - индекс действительно строится очень быстро, даже быстрее цикла по всему файлу без индекса. Причина этого - данные из файла считываются в режиме _SET_STRICTREAD, непосредственно из файла с использованием служебного буфера. Сразу же возникает мысль использовать такой же режим для поиска. Вот эта маленькая функция: http://zalil.ru/34818847 Использование функции: dbEvalDirect(bDo, bFilter) Смысл параметров такой же, как и в dbEval() Пример: aRecs := {} dbEvalDirect({|| AADD(aRecs, RecNo())}, bFilter) Функция не учитывает установки set filter, scope, и прочее, считывает полностью весь файл, от первой до последней записи. Работает еще быстрее, чем построение индекса с for, так как не создается ненужный индекс. Использовать ее можно только для rdd DBF*: DBFNTX,DBFCDX и их производных (BM*) Какие есть еще подводные камни - надо подумать, так как я эту функцию сделал спонтанно, как только появилась такая идея.

Dima: Pasha пишет: dbEvalDirect(bDo, bFilter) Вариант конечно когда нет подходящего индекса а если есть то быстрее будет конечно через dborderinfo(DBOI_SKIPREGEX,,,cRegex) сделать выборку. PS Примерчик выше

Sergy: Pasha пишет: Использование индекса с условием for - это некрасивое решение, поскольку для поиска формируется ненужный разовый индекс, при создании которого идет выборка всего файла. Согласен с этим. Поскольку при таком подходе из всех возможных вариантов будет использован наиболее медленный, с перечитыванием всего файла с начала и до конца. Банальный SET FILTER так будет себя вести только в том случае, если удовлетворяющих записей меньше, чем строк DBEDIT() на экране. Во всех остальных случаях он будет быстрее. Вот эта маленькая функция: http://zalil.ru/34818847 Использование функции: dbEvalDirect(bDo, bFilter) Смысл параметров такой же, как и в dbEval() Спасибо, изучу.

ММК: LYSK пишет: Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно). LYSK пишет: строился индекс на основании другого индекса, даже не обращаясь к записям таблицы. маска например "ИВАНОВ*" я просто для иллюстрации подхода ;-) Т.е. необходимо и достаточно наличие хотя бы одного индекса, на основе которого и происходят все последующие выборки. Вот, например , сырье .Индекс по наименованию. Выбираем ( правой кл. мыши ) поле "остаток на нач.дня" равное нулю ( или вводим любое нужное значение )

Pasha: Sergy пишет: Спасибо, изучу. Эта функция не для прерывания фильтра, я просто не стал создавать новую тему, раз уж вопрос с условной индексацией всплыл здесь опять. Назначение функции - быстрый поиск по всему файлу с произвольным условием. Можно еще добавить параметр - прерывание поиска при первом успешном попадании.

ММК: В этой выборке меня интересует сырье , для которого были поступления- соответственно другое поле и другое значение ( выборка в выборке ) Это можно делать в любой последовательности для любого кол-вы полей

Pasha: Pasha пишет: Какие есть еще подводные камни - надо подумать, Я вижу только один такой: если в процессе чтения файла через dbEvalDirect другой пользователь добавит запись, то dbEvalDirect эту запись не увидит, так как RecCount определяется перед началом выборки. Но это и есть причина такой высокой скорости: при обычной выборке каждый раз обновляется RecCount, а для этого делается fseek на конец файла, что заметно замедляет работу. Но и индексация происходит точно так же: если во время индексации другой пользователь добавит новую запись, эта запись не попадет в индекс.

Andrey: Какое решение самое лучшее для БЫСТРОГО поиска по различным полям без открытых индексов ? Решение Pasha или Dima пишет: Вариант конечно когда нет подходящего индекса а если есть то быстрее будет конечно через dborderinfo(DBOI_SKIPREGEX,,,cRegex)

Dima: Andrey Берешь базу на пару-тройку лимонов записей и делаешь 2 теста и смотришь что быстрее. PS Ответь мне на ЛС

Andrey: Dima пишет: Берешь базу на пару-тройку лимонов записей и делаешь 2 теста и смотришь что быстрее. На ЛС ответил. Помоги сделать эти тесты ? Ну очень интересно... Всем тоже узнать хочется !!! А я что нибудь другое сваяю для тебя ?

Dima: Andrey Давай мне базу да побольше и условия фильтрации (для начала хватит по одному-двум полям) или Опиши структуру базы , чем заполнять и что будем искать.

Andrey: Хорошо, делаю.

ММК: Andrey пишет: Какое решение самое лучшее для БЫСТРОГО поиска по различным полям без открытых индексов ? Решение Pasha или Dima пишет: Если воообще без индексов , то Locate :) Но и тут надо уточнить- "дикий" поиск или точный. Будет ли продолжение ( добавление следующих условий ) или "начни с начала" :))) Каждая задача имеет свое конкретное решение и сравнивать их нет смысла

Pasha: Andrey пишет: Хорошо, делаю. Тест Обьект тестирования - doma.dbf из КЛАДР, размер - 203М, более 2-х млн. записей Выражение поиска: "229"$Name Количество попаданий - 2310 Файл открыт через DBFCDX с индексом в режиме shared Тест1: поиск без управляющего индекса - 5.9 сек Тест2: поиск c управляющим индексом - 18.6 сек Тест3: построение индекса с for - 0.83 сек Тест4: поиск dbEvalDirect - 0.81 сек Вывод (он и так напрашивался): - dbEvalDirect немного быстрее индексации с for Понятно, что с файлами таких экстремальных размеров редко имеешь дело. На файле размером 40M (~300 тыс.записей) время выполнения index ... for и dbEvalDirect примерно одинаково (просто погрешность выше, чем разница в скорости) На небольшом файле размером 8М (~40 тыс.записей) index ... for выполняется за 0.05 сек, а dbEvalDirect - за 0.03 сек. (разница чувствуется)

Andrey: Pasha БОЛЬШОЕ спасибо за тесты. Я свою заготовку переслал Диме. У меня там замороченей тест получается... В смысле много полей ищется сразу в базе. Можешь ли выложить свой исходник теста ? Хочется посмотреть код профессионала. Заранее спасибо.

Pasha: Такая большая проблема сделать простейший тест, что ли ? Вот код: [pre]Field TarCV, LS Field Otkomu, Date Field Name func main Local bFor := {|| "229"$Name} //Local bFor := {|| "Охрана"$Otkomu} //Local bFor := {|| "229"$TarCV} local cf := 'doma' //local cf := 'carecs' //local cf := 'tplus' Local nSec, nk Local bDo := {|| nk ++} request dbfcdx dbUseArea(.t., 'DBFCDX', cf,, .t.) ordListAdd(cf) dbSetOrder(0) nk := 0 nSec := Seconds() dbEval(bDo, bFor) ? 'DBFCDX-0', nk, Seconds() - nSec close dbUseArea(.t., 'DBFCDX', cf,, .t.) ordListAdd(cf) nk := 0 nSec := Seconds() dbEval(bDo, bFor) ? 'DBFCDX-1', nk, Seconds() - nSec go top nk := 0 nSec := Seconds() dbEvalDirect(bDo, bFor) ? 'DBFCDX-2', nk, Seconds() - nSec nSec := Seconds() index on Code tag (cf+'1') to (cf+'1') for "229"$Name //index on Date tag (cf+'1') to (cf+'1') for "Охрана"$Otkomu //index on LS tag (cf+'1') to (cf+'1') for "229"$TarCV ? 'Index for', ordKeyCount(), Seconds()-nSec close return nil[/pre]

Pasha: Можно классифицировать скорость выборки на 3 уровня: 1. При монопольном доступе к файлу, во время индексации, и в только что написанной функции dbEvalDirect Скорость максимальная, так как ресурсы расходуются только на чтение исходного файла, и больше ни на что. При этом для монопольного доступа возможно чтение любого фрагмента файла с управляющим индексом или без него. С индексом скорость будет немного хуже. Для индексации и dbEvalDirect считывается весь файл. Поскольку letodb открывает файлы монопольно, то на него не влияют факторы, описанные ниже. 2. Для файла, открытого в режиме shared без управляющего индекса. Скорость в несколько раз хуже за счет того, что при чтении каждой записи обновляется reccount. 3. Для файла, открытого в режиме shared с управляющим индексом. Скорость еще в несколько раз хуже, чем для п.2 Причина этого, кроме момента, указанного в п.2 - блокировка индекса на чтение при чтении каждой записи. Этот момент можно резко улучшить, задав dbOrderInfo(DBOI_READLOCK,,, .t.) перед выборкой. Еще причина - выборка записи по ключу в самом индексе, т.е. чтение индекса.

Andrey: А как отобразить отобранные записи в BROWSE() ? Я сталкивался с такой задачей, т.е. есть в массиве номера записей (полученные из поиска) которые нужно отобразить на экране. Как в таком случае поступают (с учетом работы в будущем не LetoDB) ?

Dima: Andrey BM фильтр (затем browse) я же пример приводил выше

Andrey: Dima пишет: BM фильтр (затем browse) я же пример приводил выше А без BM фильтра ? Я у себя давно делал поиск по подчиненной базе. Приходилось при поиске в доп.поле записывать 0, а при нахождении 1, а потом показывать записи с кодом=1 . Это не оптимально. Вот и хочу понять как такие вещи делать ?

Dima: Без BM будет не оптимально. Как вариант складывать можно выбранные записи во временную базу Или переделать Skipper что бы он ходил по массиву с номерами записей

Pasha: Andrey пишет: А как отобразить отобранные записи в BROWSE() ? Сделать источником данных для browse не р/о, а массив. В массив загонять те данные, которые надо выдать, плюс номер записи. После выбора нужной строки массива делать dbGoto() по номеру выбранной записи из строки массива.

Andrey: Pasha пишет: Сделать источником данных для browse не р/о, а массив. В массив загонять те данные, которые надо выдать, плюс номер записи. После выбора нужной строки массива делать dbGoto() по номеру выбранной записи из строки массива. А по другому никак ? Сложновато получается... Или мне кажется только ? Минимальный код для такого BROWSE() привести можете ?

Dima: Andrey Похоже читаешь сообщения но ни чего не тестишь отсюда и не понятки. Сделай простейший пример с BM фильтром и все станет ясно. Что касается Browse то он у каждого свой под свои задачи и в любом из них есть Skipper или аналог вот его и нужно переделать если что.

Andrey: Dima пишет: Похоже читаешь сообщения но ни чего не тестишь отсюда и не понятки. Делаю. На этой неделе выложу.

Sergy: Andrey пишет: А как отобразить отобранные записи в BROWSE() ? Я сталкивался с такой задачей, т.е. есть в массиве номера записей (полученные из поиска) которые нужно отобразить на экране. Как в таком случае поступают (с учетом работы в будущем не LetoDB) ? Со времен Clipper, когда нужных записей в большой таблице мало - выяснил, что гораздо эффективнее их считать в массив, а потом только их и показывать. Примерно так: [pre2] aRx:={} GO TOP DO WHILE !EOF() IF .... AADD(aRx,RECNO()) ENDIF SKIP ENDDO DbViewByArray(a+1,1,MAXROW()-5,MAXCOL()-1,aValues[1],"CallBackFunc",aRx,@nPos)[/pre2] где: [pre2] * ------------------------------------------------ * FUNC DbViewByArray(nTop,nLeft,nBottom,nRight,; cValues,cProcName,aRecNumbers,nPos) LOCAL i,bValues DEFAULT nPos TO 1 PRIV dbv_more:=TRUE,txt,rxn PRIV user_func:=cProcName IF EMPTY(cValues) .OR. EMPTY(cProcName) ShowAlert("DbViewByArray: No Parameters.") RETURN ELSEIF (VALTYPE(aRecNumbers) # "A") .OR. (LEN(aRecNumbers) = 0) ShowAlert("DbViewByArray: нет записей") RETURN ENDI bValues := {||&cValues} // блок кода для ускорения работы rxn := aRecNumbers // сразу копируем ссылку на массив DO WHILE dbv_more ////////////////////////////////////////////////// осн.цикл txt:=ARRAY(LEN(aRecNumbers)) FOR i:=1 TO LEN(aRecNumbers) GO aRecNumbers[ i ] txt[ i ] := EVAL(bValues) NEXT i @ nTop+LEN(txt),nLeft CLEAR TO nBottom,nRight // очистка конца экрана DbView2(0,nPos,save_pos) // redraw screen nPos:=ACHOICE(nTop,nLeft,nBottom,nRight,txt,,"DbView2",nPos,save_pos) ENDDO RETURN * ----------------------------- * FUNC DbView2(mode,index,scrn_pos) // call-back user func here! LOCAL user_result IF (index > LEN(txt)) .OR. (index < 1) index := 1 ENDI save_index := index save_pos := scrn_pos GO rxn[index] user_result := &user_func (TranslateMsg(mode),rxn,index) // вызов call-back функции пользователя save_rx := RECNO() DO CASE CASE user_result = DE_CONT; RETURN AC_CONT CASE user_result = DE_ABORT; dbv_more:=FALSE; RETURN AC_SELECT CASE user_result = DE_REFRESH; dbv_more:=TRUE; RETURN AC_SELECT CASE user_result = DBVIEW_DOWN; PutInKbd(CHR(K_DOWN)); RETURN AC_CONT CASE user_result = DBVIEW_UP; PutInKbd(CHR(K_UP)); RETURN AC_CONT OTHERWISE RETURN AC_CONT ENDC RETURN AC_CONT * ----------------------------- * [/pre2]

Andrey: Dima пишет: Похоже читаешь сообщения но ни чего не тестишь отсюда и не понятки. Сделал тест на базу 101тыс. записей. Реально рабочий пример. В базе 12 полей FAM1-FAM12, NAME1-NAME12, OTCH1-OTCH12 Делать поиск сразу по этим полям сложно. SET FILTER и LOCATE успешно ищет. Правда показ в BROWSE() по SET FILTER - тормоза ! Время поиска просто очень мало 1сек. Может у меня комп такой... На сети пока не тестил, на след.неделе сделаю. Поиск по SEEK не стал реализовывать. Что-то очень сложный алгоритм получается... dbEvalDirect() - не работает, слишком большое условие поиска (больше 900 символов). Павел, если можно сделать большую строку поиска, то очень хорошо, если нет, то не страшно. Dima пишет: пример с BM фильтром Жду от Димы. Вообще кто, что можете порекомендовать, пишите. Я не смотря на долгую работу с Клипером, всех тонкостей не знаю. Сам проект на хХарборе 1.2.3 http://files.mail.ru/5D8A880F51054F7BBB3A279FB1E279EA

Dima: Andrey пишет: Жду от Димы. Андрей выше чуть я давал пример как раз на несколько полей и BM фильтром.

Andrey: Dima пишет: Андрей выше чуть я давал пример как раз на несколько полей и BM фильтром. у меня в тесте, несколько сложнее поиск. (В базе 12 полей FAM1-FAM12, NAME1-NAME12, OTCH1-OTCH12) По одному полю делать понятно как. А как делать в моем случае ? Прими участие в составление теста !

Dima: Andrey пишет: По одному полю делать понятно как. Там чуть ниже есть пример для 3-х полей (то же самое сделать можно для 12 полей) ПС Ключевое слово в сообщении CrazyFilter

SergKis: Andrey пишет:dbEvalDirect() - не работает, слишком большое условие поиска (больше 900 символов) Зачем так мучить выражение, можно (разбив на части и поместив в массив) примерно так: [pre2] FUNC MyFltr( aBlock ) LOCAL i FOR i := 1 TO len(aBlock) IF ! EVal(aBlock[ i ] RETURN .F. ENDIF NEXT RETURN .T. [/pre2]

SergKis: Andrey После dbEvalDirect(), без BM фильтра можно положить, полученный массив в dbf MEMIO (если не проходит массив в browse, как писал Pasha) и на него browse, добавив в skipper перемещение на нужную RecNo в основном алисе (как писал Dima) и ВСЕ старое должно заработать.

Andrey: SergKis Спасибо БОЛЬШОЕ !

Pasha: Andrey пишет: dbEvalDirect() - не работает, слишком большое условие поиска (больше 900 символов). Павел, если можно сделать большую строку поиска, то очень хорошо, если нет, то не страшно. Что еще за строка символов ? 2-й параметр - это блок кода, который должен вернуть логическое значение. Точно так же, как и в dbEval().

Dima: Pasha Он не пытается понять что пишут мне кажется.............подавай готовый код и тд и тп , возможно устал

Andrey: Pasha пишет: Что еще за строка символов ? 2-й параметр - это блок кода, который должен вернуть логическое значение. Точно так же, как и в dbEval(). Pasha пишет выше: func main Local bFor := {|| "Охрана"$Otkomu} Local bDo := {|| nk ++} ........ dbEvalDirect(bDo, bFor) .......... В моем случае: cFilterTo:= '("ИВАНОВ"$UPPER(FAM1).AND."ИВАН"$UPPER(NAME1).AND."ИВАНОВИЧ"$UPPER(OTCH1)).OR.("ИВАНОВ"$UPPER(FAM2).... ' - и т.д. Длина строки поиска=956 символов FUNCTION MyFindEvalDirect(cFilterTo,cFio) Local bDo := {|| AADD(aRecs, RECNO()) } Local bFilter := {|| cFilterTo } ...... dbEvalDirect(bDo, bFilter) Может я неправильно описал ? Извиняюсь за своё косноязычее....

Andrey: Dima пишет: Он не пытается понять что пишут мне кажется.............подавай готовый код и тд и тп , возможно устал Да пытаюсь понять и сделать применительно к своей задаче. Из-за этого и отдельный пример сделал. Устал, это точно. Разбираюсь с твоим CrazyFilter.... У меня в тесте - LOCATE отрабатывает за 0,01 сек. (удивительно быстро..., всегда считал его медленным) Там код вот такой есть: DBSETORDER(0) LOCATE FOR &cFilterTo DO WHILE Found() // help xHarbour Language Reference Guide nRec++ AADD( aRecno, RECNO() ) // записать в массив CONTINUE ENDDO Но почему то не получается как у тебя: RDDSETDEFAULT( "BMDBFCDX" ) SELECT DOGOVOR BM_DBSETFILTERARRAY(aRecno) BROWSE()

Dima: Andrey пишет: Но почему то не получается как у тебя: RDDSETDEFAULT( "BMDBFCDX" ) Harbour ?

Andrey: Dima пишет: Harbour ? хХарбор 1.2.3 Пример здесь - выше. Исправленных файл из проекта. http://files.mail.ru/0FB87DC650FA43E0969EB86D82B447A0

Dima: Andrey Вот живой пример (фильтр по 3-м полям) для HARBOUR (В Иксах не проверял так как их нет у меня) [pre2] #include "dbinfo.ch" REQUEST BMDBFNTX Proc main() FIELD F1,F2,F3 RDDSETDEFAULT( "BMDBFNTX" ) cls aeval(directory("tst.*"),{|x|ferase(x[1])}) dbCreate("tst", {{"F1", "C", 20, 0},{"F2", "c", 20, 0},{"F3", "c", 20, 0}}) USE tst while lastrec()<100000 dbappend() F1:= strzero(recno(),10)+chr(recno()%26+asc("A")) F2:= strzero(recno(),10)+chr(recno()%26+asc("B")) F3:= strzero(recno(),10)+chr(recno()%26+asc("C")) enddo INDEX ON F1 TO tst1 INDEX ON F2 TO tst2 additive INDEX ON F3 TO tst3 additive if CrazyFilter({{1,".*101.*A"},{2,".*101.*B"},{3,".*101.*C"}}) browse() else ? "Нет подходящих записей" endif return ****************** Func CrazyFilter(par) local i local amas local cRegex local ret:=.t. for i=1 to len(par) amas:={} if !empty(par[ i ][2]) cRegex:=par[ i ][2] cRegex:=HB_REGEXCOMP(cRegex) dbsetorder(par[ i ][1]) dbgotop() while !eof() if HB_REGEXHAS(cRegEx,ordkeyval()) aadd(amas,recno()) endif dborderinfo(DBOI_SKIPREGEX,,,cRegex) enddo BM_DBSETFILTERARRAY(amas) endif next if len(amas)==0 dbclearfilter() ret:=.f. endif return ret [/pre2] Сборка c:\hb32\bin\hbmk2 t -lrddbm

Sergy: Andrey пишет: В моем случае: cFilterTo:= '("ИВАНОВ"$UPPER(FAM1).AND."ИВАН"$UPPER(NAME1).AND."ИВАНОВИЧ"$UPPER(OTCH1)).OR.("ИВАНОВ"$UPPER(FAM2).... ' - и т.д. Не очень понимаю, какая задача может потребовать столь чудовищной структуры данных - 12 ФИО в одной записи... Точно от этого никак не избавиться ?

Andrey: Sergy пишет: Точно от этого никак не избавиться ? Было так заведено... году так в 1998 ... Тогда мемо поля пропадали и не было Харбора, а только Клипер. Пришлось извратиться... Sergy пишет: какая задача может потребовать столь чудовищной структуры данных - 12 ФИО в одной записи... Приватизация жилья. 12 полей Фамилий + 12 полей Имен + 12 полей Отчеств на ОДНУ запись ! Живет и работает программа со свистом... : Стоит ли переделывать рабочую программу, если поиск сейчас занимает 01 сек ?

Andrey: Тесты на сетке: Путь к БД: \\SERVERXP\DBF-Search\DBF\ Инфо о БД: Кол-во записей в БД = 101000 OS: Windows 8 Professional 6.02.9200 ВСЕГО ЗАТРАЧЕНО на поиск (SET FILTER) = 01 мин. 47 сек. ВСЕГО ЗАТРАЧЕНО на поиск (Locate) = 29 сек. Многовато будет....

Andrey: Dima пишет: Вот живой пример (фильтр по 3-м полям) для HARBOUR (В Иксах не проверял так как их нет у меня) Нет в хХарборе HB_REGEXHAS Чем можно заменить ?

Dima: Andrey пишет: Нет в хХарборе HB_REGEXHAS Чем можно заменить ? http://clipper.borda.ru/?1-4-0-00000939-000-0-0-1383983897

Sergy: Как вариант - сделать примерно так: [pre2]FUNC MyFilter(cName1,cName2,cName3) LOCAL i,result result := FALSE FOR i:=1 TO 12 IF cName1 $ &("FAM"+NTRIM(i)) .AND. ; cName2 $ &("NAME"+NTRIM(i)) .AND. ; cName3 $ &("OTCH"+NTRIM(i)) result := TRUE EXIT NEXT i RETURN result [/pre2] А если нехота использовать макросы, можно получить доступ через FIELDPOS() - если записей очень много, есть подозрение что он будет работать быстрее. Только нужно определиться, в каком порядке идут имена, отчества и фамилии. И в последствии постараться не менять структуру. А потом уже фильтровать на основании блока кода {|| MyFilter("ИВАНОВ","ИВАН","ИВАНОВИЧ")} Дай погудю немного: Andrey пишет: Приватизация жилья. 12 полей Фамилий + 12 полей Имен + 12 полей Отчеств на ОДНУ запись ! Живет и работает программа со свистом... : Стоит ли переделывать рабочую программу, если поиск сейчас занимает 01 сек ? Ниче не нужно переделывать. Все наши проги работают лучше всех, несмотря на классический пример неправильной структуры данных. В одной приватизации может участвовать два человека, в другой - три, а десяток пустых ФИО (т.е. примерно тридцать полей) будут болтаться в записи... А если нужно будет приватизировать одну жилплощадь на 13 человек - одного придется обломать... А потом возникают "спасите-помогите, строка поиска занимает килобайт и препроцессор/макрокомпилер не может ее проглотить..."

Pasha: Andrey пишет: В моем случае: cFilterTo:= '("ИВАНОВ"$UPPER(FAM1).AND."ИВАН"$UPPER(NAME1).AND."ИВАНОВИЧ"$UPPER(OTCH1)).OR.("ИВАНОВ"$UPPER(FAM2).... ' - и т.д. Длина строки поиска=956 символов FUNCTION MyFindEvalDirect(cFilterTo,cFio) Local bDo := {|| AADD(aRecs, RECNO()) } Local bFilter := {|| cFilterTo } ...... dbEvalDirect(bDo, bFilter) Может я неправильно описал ? Извиняюсь за своё косноязычее.... Не буду даже пытаться объяснить, что к чему, просто покажу, как надо сделать: // Создание блока кода из выражения поиска bFilter := &("{||" + cFilterTo + "}") ...... dbEvalDirect(bDo, bFilter)

Andrey: Pasha пишет: Не буду даже пытаться объяснить, что к чему, просто покажу, как надо сделать: Спасибо БОЛЬШОЕ ! Как увидел, так сразу понял, раньше так делал. Просто уже глаза замылились....

Dima: Andrey пишет: Просто уже глаза замылились Глазам отдых нужен !

Andrey: dbEvalDirect() - заработал. Но Browse() ломается при показе после него и программ вылетает. Массив создается нормально. // Создание блока кода из выражения поиска bFilter := &("{||" + cFilterTo + "}") SELECT DOGOVOR dbEvalDirect(bDo, bFilter) BROWSE(1,0,MAXROW(),MAXCOL()) Как починить dbEvalDirect() или после него нельзя вызывать browse() ? C dbeval() таких проблем нет.

SergKis: Pasha dbEvalDirect() портит что-то ... prg: RddSetDefault( "DBFNTX" ) USE ( 'TEST' ) ALIAS TEST a := {} b := {|| right(R_32, 2) $ '02,04,06' } msglog(RecNo(),Alias()) i := seconds() dbEvalDirect({|| aAdd(a, RecNo()) }, b) msglog(seconds()-i,a, RecNo(),alias()) // aEval(a, {|xV,nE| msglog(nE, xV) }) GO TOP msglog(RecNo(),Alias()) USE // это 49 строка MAIN hb_out.log: Application Internal Error - C:\BK9\TEST\_TEST\INF\TEST.EXE Terminated at: 2013.11.26 12:23:40 Unrecoverable error 6005: Exception error: Exception Code:C0000005 Exception Address:00406C6A EAX:20202020 EBX:00000000 ECX:0000010C EDX:00000190 ESI:001F565C EDI:00000000 EBP:01271C88 CS:EIP:001B:00406C6A SS:ESP:0023:0012FE04 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010202 CS:EIP: 8B 3C 28 A1 00 E7 52 00 33 F8 39 47 20 74 0A 5F SS:ESP: 00000000 00232088 0042A8F0 00000094 00407443 00000000 01271C90 0043C974 01271C94 001F565C 0021CA98 00000000 0045121F 001F565C 00000000 001F565C C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00406C6A 01271C88 20202020 20202020 20202020 98302020 20202051 34302020 3231312F 30313130 37343131 35352020 Modules: 0x00400000 0x0013E000 C:\BK9\TEST\_TEST\INF\TEST.EXE 0x777C0000 0x0013C000 C:\Windows\SYSTEM32\ntdll.dll 0x76AB0000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75B00000 0x0004B000 C:\Windows\system32\KERNELBASE.dll 0x771E0000 0x000C9000 C:\Windows\system32\USER32.dll 0x770E0000 0x0004E000 C:\Windows\system32\GDI32.dll 0x779E0000 0x0000A000 C:\Windows\system32\LPK.dll 0x76EC0000 0x0009D000 C:\Windows\system32\USP10.dll 0x77130000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x75D70000 0x00C4A000 C:\Windows\system32\SHELL32.dll 0x769C0000 0x00057000 C:\Windows\system32\SHLWAPI.dll 0x74850000 0x0019E000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\COMCTL32.dll 0x773C0000 0x000A0000 C:\Windows\system32\ADVAPI32.dll 0x76B90000 0x00019000 C:\Windows\SYSTEM32\sechost.dll 0x77680000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x76F60000 0x0015C000 C:\Windows\system32\ole32.dll 0x77330000 0x0008F000 C:\Windows\system32\OLEAUT32.dll 0x770C0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x77910000 0x000CC000 C:\Windows\system32\MSCTF.dll Called from DBCLOSEAREA(0) Called from MAIN(49) in .\PRG\TEST.txt ------------------------------------------------------------------------ мой log, тест работы: 1 TEST 0.5770 ARRAY[51218] 206903 TEST 1 TEST

Pasha: SergKis пишет: Pasha dbEvalDirect() портит что-то ... Поправил, переименовал функцию в dbfEval, добавил поддержку всех параметров, как в dbEval, сборку под xharbour: http://files.mail.ru/A324711CF8A94781808E50C7BEB48B30

SergKis: Pasha prg: a := {} dbfEval({|| aAdd(a, RecNo()) }, b) GO TOP browse() USE без Browse не снимается с Browse валится hb_out.log: [pre2] Application Internal Error - C:\BK9\TEST\_TEST\INF\_dbfEval.exe Terminated at: 2013.11.27 19:32:34 Unrecoverable error 6005: Exception error: Exception Code:C0000005 Exception Address:00422969 EAX:20202020 EBX:001E76AC ECX:20202020 EDX:80808080 ESI:001E153C EDI:00000000 EBP:0012FC70 CS:EIP:001B:00422969 SS:ESP:0023:0012FC64 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010282 CS:EIP: 8B 01 8B 4B 10 03 C2 C1 E1 02 03 C1 8B 18 EB 12 SS:ESP: 00000000 001E153C 001E76AC 0012FC9C 0041238E 001E76AC 0012FDC8 0012FCEC 004E44E0 00422299 00417DAB 0012FDC8 0012FCEC 004F18B8 0012FCC8 004085BA C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00422969 0012FC70 0012FC9C 0041238E 001E76AC 0012FDC8 0012FCEC 004E44E0 00422299 00417DAB 0012FDC8 0012FCEC 0041238E 0012FC9C 0012FCC8 004085BA 001E76AC 004E44E0 0012FCB4 004F18B8 00000022 00000003 00000000 00000000 004085BA 0012FCC8 0012FCE0 0040BAB7 00000000 0012FDC8 0012FCEC 004E4EB0 0040BAB7 0012FCE0 0012FD14 004651FF 00000000 00000001 0012FD38 004E4430 004085F9 004F18B8 00000015 00000003 004651FF 0012FD14 0012FD2C 0040BAB7 00000001 0012FDC8 0012FD38 004E4EB0 0040BAB7 0012FD2C 0012FD60 00466ABC 00000001 00000000 00000000 004E46D0 004085F9 004F18B8 00000013 00000003 00466ABC 0012FD60 0012FD78 0040BAB7 001E0000 0012FDC8 00000000 004E0770 0040BAB7 0012FD78 0012FDA4 00466F66 00000000 0012FD90 004085F9 004F18B8 00000003 00000003 00000000 00A70004 00466F66 0012FDA4 0012FDBC 0040BAB7 00000000 0012FDC8 00000000 004E0BD0 0040BAB7 0012FDBC 004E0C15 0045014B 00000000 00000000 004F18B8 0012FDF8 004DC600 00000000 004F18B8 0040843C Modules: 0x00400000 0x00103000 C:\BK9\TEST\_TEST\INF\_dbfEval.exe 0x77640000 0x0013C000 C:\Windows\SYSTEM32\ntdll.dll 0x76D40000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75770000 0x0004B000 C:\Windows\system32\KERNELBASE.dll 0x769C0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x771B0000 0x0004E000 C:\Windows\system32\GDI32.dll 0x777A0000 0x0000A000 C:\Windows\system32\LPK.dll 0x76C90000 0x0009D000 C:\Windows\system32\USP10.dll 0x77030000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x777B0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x770E0000 0x000CC000 C:\Windows\system32\MSCTF.dll Called from (b)EVAL(0) Called from TBROWSE:READRECORD(0) in ../../../tbrowse.prg Called from TBROWSE:STABILIZE(0) in ../../../tbrowse.prg Called from TBROWSE:FORCESTABLE(0) in ../../../tbrowse.prg Called from BROWSE(0) in ../../../browse.prg Called from MAIN(45) in _dbfEval.prg ------------------------------------------------------------------------ Application Internal Error - C:\BK9\TEST\_TEST\INF\_dbfEval.exe Terminated at: 2013.11.27 19:32:37 Unrecoverable error 6005: Exception error: Exception Code:C0000005 Exception Address:00422969 EAX:20202020 EBX:001E76AC ECX:20202020 EDX:80808080 ESI:001E153C EDI:00000000 EBP:0012FC70 CS:EIP:001B:00422969 SS:ESP:0023:0012FC64 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010282 CS:EIP: 8B 01 8B 4B 10 03 C2 C1 E1 02 03 C1 8B 18 EB 12 SS:ESP: 00000000 001E153C 001E76AC 0012FC9C 0041238E 001E76AC 0012FDC8 0012FCEC 004E44E0 00422299 00417DAB 0012FDC8 0012FCEC 004F18B8 0012FCC8 004085BA C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00422969 0012FC70 0012FC9C 0041238E 001E76AC 0012FDC8 0012FCEC 004E44E0 00422299 00417DAB 0012FDC8 0012FCEC 0041238E 0012FC9C 0012FCC8 004085BA 001E76AC 004E44E0 0012FCB4 004F18B8 00000022 00000003 00000000 00000000 004085BA 0012FCC8 0012FCE0 0040BAB7 00000000 0012FDC8 0012FCEC 004E4EB0 0040BAB7 0012FCE0 0012FD14 004651FF 00000000 00000001 0012FD38 004E4430 004085F9 004F18B8 00000015 00000003 004651FF 0012FD14 0012FD2C 0040BAB7 00000001 0012FDC8 0012FD38 004E4EB0 0040BAB7 0012FD2C 0012FD60 00466ABC 00000001 00000000 00000000 004E46D0 004085F9 004F18B8 00000013 00000003 00466ABC 0012FD60 0012FD78 0040BAB7 001E0000 0012FDC8 00000000 004E0770 0040BAB7 0012FD78 0012FDA4 00466F66 00000000 0012FD90 004085F9 004F18B8 00000003 00000003 00000000 00A70004 00466F66 0012FDA4 0012FDBC 0040BAB7 00000000 0012FDC8 00000000 004E0BD0 0040BAB7 0012FDBC 004E0C15 0045014B 00000000 00000000 004F18B8 0012FDF8 004DC600 00000000 004F18B8 0040843C Modules: 0x00400000 0x00103000 C:\BK9\TEST\_TEST\INF\_dbfEval.exe 0x77640000 0x0013C000 C:\Windows\SYSTEM32\ntdll.dll 0x76D40000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75770000 0x0004B000 C:\Windows\system32\KERNELBASE.dll 0x769C0000 0x000C9000 C:\Windows\system32\USER32.DLL 0x771B0000 0x0004E000 C:\Windows\system32\GDI32.dll 0x777A0000 0x0000A000 C:\Windows\system32\LPK.dll 0x76C90000 0x0009D000 C:\Windows\system32\USP10.dll 0x77030000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x777B0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x770E0000 0x000CC000 C:\Windows\system32\MSCTF.dll Called from (b)EVAL(0) Called from TBROWSE:READRECORD(0) in ../../../tbrowse.prg Called from TBROWSE:STABILIZE(0) in ../../../tbrowse.prg Called from TBROWSE:FORCESTABLE(0) in ../../../tbrowse.prg Called from BROWSE(0) in ../../../browse.prg Called from MAIN(45) in _dbfEval.prg ------------------------------------------------------------------------ [/pre2] содержимое hb_out.log получено за один запуск exe. вариант со стандартным dbEval работает.

SergKis: Pasha это hb 3.2 bcc. под MSVC и hb 2.0 без browse валится на USE закрытия. hb_out.log:[pre2] Application Internal Error - C:\BK9\TEST\_TEST\INF\TEST.EXE Terminated at: 2013.11.27 19:45:04 Unrecoverable error 6005: Exception error: Exception Code:C0000005 Exception Address:00406D3A EAX:20202020 EBX:00000000 ECX:0000014C EDX:00000190 ESI:003D56D4 EDI:00000000 EBP:003F1C88 CS:EIP:001B:00406D3A SS:ESP:0023:0012FE04 DS:0023 ES:0023 FS:003B GS:0000 Flags:00010202 CS:EIP: 8B 3C 28 A1 20 E7 52 00 33 F8 39 47 20 74 0A 5F SS:ESP: 00000000 00701F90 0042A9C0 00000094 00407513 00000000 003F1C90 0043CC04 003F1C94 003D56D4 0054CA98 00000000 004514AF 003D56D4 00000000 003D56D4 C stack: EIP: EBP: Frame: OldEBP, RetAddr, Params... 00406D3A 003F1C88 20202020 20202020 20202020 98302020 20202051 34302020 3231312F 30313130 37343131 35352020 Modules: 0x00400000 0x0013E000 C:\BK9\TEST\_TEST\INF\TEST.EXE 0x77640000 0x0013C000 C:\Windows\SYSTEM32\ntdll.dll 0x76D40000 0x000D4000 C:\Windows\system32\kernel32.dll 0x75770000 0x0004B000 C:\Windows\system32\KERNELBASE.dll 0x769C0000 0x000C9000 C:\Windows\system32\USER32.dll 0x771B0000 0x0004E000 C:\Windows\system32\GDI32.dll 0x777A0000 0x0000A000 C:\Windows\system32\LPK.dll 0x76C90000 0x0009D000 C:\Windows\system32\USP10.dll 0x77030000 0x000AC000 C:\Windows\system32\msvcrt.dll 0x75A50000 0x00C4A000 C:\Windows\system32\SHELL32.dll 0x759F0000 0x00057000 C:\Windows\system32\SHLWAPI.dll 0x745C0000 0x0019E000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\COMCTL32.dll 0x773A0000 0x000A0000 C:\Windows\system32\ADVAPI32.dll 0x77780000 0x00019000 C:\Windows\SYSTEM32\sechost.dll 0x76E60000 0x000A1000 C:\Windows\system32\RPCRT4.dll 0x76860000 0x0015C000 C:\Windows\system32\ole32.dll 0x76FA0000 0x0008F000 C:\Windows\system32\OLEAUT32.dll 0x777B0000 0x0001F000 C:\Windows\system32\IMM32.DLL 0x770E0000 0x000CC000 C:\Windows\system32\MSCTF.dll Called from DBCLOSEAREA(0) Called from MAIN(65) in .\PRG\TEST.txt ------------------------------------------------------------------------ [/pre2]

Andrey: Pasha Не собирается под xHarbour 1.2.3 Intl. (SimpLex) (Build 20130903) Copyright 1999-2013, http://www.xharbour.org http://www.harbour-project.org/ Compiling 'DBFEVAL.PRG'... Generating C source output to 'obj\DBFEVAL.c'... Done. Building object module for 'obj\DBFEVAL.c' using C compiler 'BCC32' as defined in 'Z:\xHARBOUR\BIN\harbour.cfg'... Exec: BCC32 -c -D__EXPORT__ -IZ:\xHARBOUR\include -d -LZ:\xHARBOUR\lib -oobj\DBFEVAL.obj obj\DBFEVAL.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland obj\DBFEVAL.c: Warning W8075 DBFEVAL.PRG 32: Suspicious pointer conversion in function HB_FUN_DBFEVAL Warning W8075 DBFEVAL.PRG 37: Suspicious pointer conversion in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 50: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 54: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL *** 2 errors in Compile *** Done. Deleting: "obj\DBFEVAL.c" Done. Lines 2, Functions/Procedures 0, pCodes 0

ММК: Andrey пишет: Не собирается под Пока возникли небольшие технические трудности я вас немножко развлеку. Необходимость в функции поиска возникает регулярно. И регулярно появляются разные варианты (но в Харбор , как стандартную функцию их почему то не включают :) ) Вот один из таких :)) http://files.mail.ru/4B45968E44E6429AB810802AB86AE7DF База shared , без индекса. Записей чуть больше трех с половиной лимонов. При поиске используются стандартные управляющие символы "?" и "*" . Анализ кодировки ( дос или win) и формирование массива с номерами найденных записей. Формат функции : поле, шаблон поиска, кодировка. #include "FiveWin.ch" Function Main Local nTime,n:=0 Local popa:={}, vr RDDSetDefault('DBFCDX') Use dr new shared nTime := Seconds() while (vr:=FLocate('TYJ','D?d*','D'))<>-1 N:=n+1 aadd(popa,vr) enddo MsgInfo( Seconds() - nTime ) for vr=1 to len(popa) MsgInfo( popa[vr] ) next Return NIL Скорость ,естественно , зависит от машины. Есть небольшая погрешность - память очищается не "до" , а "после " поэтому запустите примерчик два-три раза.... На моей машине это приблизительно 0.7 секунды

SergKis: MMK пишет:На моей машине это приблизительно 0.7 секунды у меня ~ 1.37. но в данном примере 4 поля и длина записи 40, в моем 92 и 912. Функция dbfEval работает в 4 раза быстрее стабильно: [pre2] Do while: 2.2470 ARRAY[51218] 206904 DbEval : 2.2460 ARRAY[51218] 206904 DbfEval : 0.5140 ARRAY[51218] 206903 [/pre2]

Dima: ММК пишет: FLocate Что за черный ящик ?

ММК: SergKis пишет: но в данном примере 4 поля и длина записи 40, в моем 92 и 912 Ну это понятно, понятно.... А не затруднит Вас сделать поиск по моей базке и сформировать массив? Шаблон D?d* . Т.е. с учетом ? и * . Для чистоты эксперемента :)))) Dima пишет: Что за черный ящик ? Да старые архивы перебирал :) Нашел Fast Locate

Dima: ММК пишет: Нашел Fast Locate Исходничек тоже есть ? :)

SergKis: MMK пишет: А не затруднит ... Сделал: маску превратил в: upper(left(TYJ,1)+subs(TYJ,3,1)) == 'DD' [pre2] Do while: 35.1160 ARRAY[5] 3506491 DbEval : 35.7870 ARRAY[5] 3506491 DbfEval : 7.3320 ARRAY[5] 3506490 [/pre2] Результат FastLocate впечатляет !

Pasha: SergKis пишет: без Browse не снимается с Browse валится hb_out.log: Я пока в затруднении. Дело в том, что я таких ошибок не получаю, никакого последействия нет. Вот прицепил эту функцию к своему dbedit, тоже все работает. Да и кода в dbfEval с гулькин нос, непонятно, откуда взяться ошибке.

Andrey: Pasha Не собирается под xHarbour 1.2.3 Intl. (SimpLex) (Build 20130903) Copyright 1999-2013, http://www.xharbour.org http://www.harbour-project.org/ Compiling 'DBFEVAL.PRG'... Generating C source output to 'obj\DBFEVAL.c'... Done. Building object module for 'obj\DBFEVAL.c' using C compiler 'BCC32' as defined in 'Z:\xHARBOUR\BIN\harbour.cfg'... Exec: BCC32 -c -D__EXPORT__ -IZ:\xHARBOUR\include -d -LZ:\xHARBOUR\lib -oobj\DBFEVAL.obj obj\DBFEVAL.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland obj\DBFEVAL.c: Warning W8075 DBFEVAL.PRG 32: Suspicious pointer conversion in function HB_FUN_DBFEVAL Warning W8075 DBFEVAL.PRG 37: Suspicious pointer conversion in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 50: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 54: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL *** 2 errors in Compile *** Done. Deleting: "obj\DBFEVAL.c" Done. Lines 2, Functions/Procedures 0, pCodes 0

SergKis: Pasha собрал как есть: http://gfile.ru/a2yK5 browse перестал слетать и пару раз даже без снятия отработал.

ММК: SergKis пишет: Do while: 35.1160 ARRAY[5] 3506491 DbEval : 35.7870 ARRAY[5] 3506491 DbfEval : 7.3320 ARRAY[5] 3506490 Результат FastLocate впечатляет ! Спасибо , что уделили внимание ! Pasha пишет: Я пока в затруднении. Дело в том, что я таких ошибок не получаю, никакого последействия нет. Если у Вас есть желание и время я пришлю Вам исходник. Может из двух вариантов получится что хорошее для народа :)) Dima пишет: Исходничек тоже есть ? :) Вот ,собственно говоря , ответ :)))

Dima: ММК пишет: Если у Вас есть желание и время я пришлю Вам исходник. Может из двух вариантов получится что хорошее для народа :)) Ждем Пашу !

Pasha: Да я уже со всем разобрался, вечером скину. Должен сказать, что в letodb выборка по установленному фильтру по скорости сопоставима с dbfEval, (хотя чуть медленнее) Но так и должно быть, поскольку letodb работает в монопольном режиме. А насчет fast locate - если его скорость сопоставима или лучше, чем в dbfEval, есть смысл на него глянуть.

ММК: Pasha пишет: есть смысл на него глянуть. отправил

Pasha: Ссылка на исправленный dbfEval: http://files.mail.ru/10FD94F47C824895BC5C8CB1913BC973 По поводу dbFLocate. Также используются файловые операции. Не тестировал, только смотрел сырцы. Поиск выполняется по одному полю, независимо от его типа, поле считывается как строка, поиск выполняется по hb_strMatchWild. Если нужен поиск по одному полю, то dbFLocate будет немного быстрее, чем dbfEval. Но dbfEval более универсален, так как в качестве выражения для поиска можно использовать произвольный блок кода.

Andrey: Pasha пишет: Ссылка на исправленный dbfEval: Не собирается опять проект на хХарборе с этим файлом. Вот такая ошибка: xHarbour 1.2.3 Intl. (SimpLex) (Build 20130903) Copyright 1999-2013, http://www.xharbour.org http://www.harbour-project.org/ Compiling 'DBFEVAL.PRG'... Generating C source output to 'obj\DBFEVAL.c'... Done. Building object module for 'obj\DBFEVAL.c' using C compiler 'BCC32' as defined in 'Z:\xHARBOUR\BIN\harbour.cfg'... Exec: BCC32 -c -D__EXPORT__ -IZ:\xHARBOUR\include -d -LZ:\xHARBOUR\lib -oobj\DBFEVAL.obj obj\DBFEVAL.c Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland obj\DBFEVAL.c: Warning W8075 DBFEVAL.PRG 29: Suspicious pointer conversion in function HB_FUN_DBFEVAL Warning W8075 DBFEVAL.PRG 36: Suspicious pointer conversion in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 49: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 53: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL *** 2 errors in Compile *** Done. Deleting: "obj\DBFEVAL.c" Done. Lines 2, Functions/Procedures 0, pCodes 0

ММК: Pasha пишет: Если нужен поиск Понимаете , Паша , идея была в том что бы объеденить эти функции т.к. каждая из них имеет свои достоинства. Скажем по параметру запускать один из вариантов. Поиск по одному полю гораздо быстрее и наличие MatchWild очень вожно. dbfEval хорош для общего поиска. Но поиск это поиск , а фильтр это фильтр :)) Для себя я это представляю ( и делаю ) , как три разные задачи; Поиск. Фильтр, когда он ставится один раз и под заранее оговоренный отчет. Вложенные фильтры-когда пользователь ставит каждый последующий в зависимости от результата предыдущего. Т.е. "творчески" работает с базой :) И варианты могут быть любые, соответственно не очень удобно создавать на все поля индексы ( особенно , если этих полей 100-150 ) и (или) писать обработку массивов для такой ситуации. Для вложенных фильтров использую не index.. for , а index on ... to tsmy_idx for !deleted() CUSTOM ADDITIVE Он создается на локальной машине и дальнейшая работа идет не с базой , а с индексом. И мы его не перестраивааем , а корректируем. Например передается вид операции ( больше, меньше и т.д. ) и необходимое значение. Поэтому любой пользователь может ставить свой филтр вне зависимости от других. А дальще - .... myblock:=&('{||iif('+bloo+alltrim(znak)+'"'+alltrim(wot)+'",ORDKEYADD("TSMY_IDX","tsmy_idx.cdx",'+mykey+'),)}') ... dbeval(myblock) или , соответственно - myblock:=&('{||iif('+bloo+alltrim(znak)+'"'+alltrim(wot)+'",,ORDKEYDEL("TSMY_IDX"))}') Можно использовать и "вилд" фильтр А теперь просто "рефрешь" бровса. По ощущениям "прорисовка экран" идет медленнее , чем работа фильтра. Новое условие на этот филтр - новая корректировка dbeval(myblock)

Dima: Andrey пишет: Error E2451 DBFEVAL.PRG 49: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL Error E2451 DBFEVAL.PRG 53: Undefined symbol 'hDataFile' in function HB_FUN_DBFEVAL Не уверен но возможно вместо hDataFile нужно написать pDataFile

Pasha: Наконец-то разобрался со сборкой для xHarbour SVN Оказывается, там размерность типов данных ULONG и HB_ULONG разная Скачать исходник dbfeval: http://zalil.ru/34858902

Andrey: Спасибо БОЛЬШОЕ Pasha ! Компилируется нормально.

Andrey: А почему в dbfEval() если есть условие ".AND.!DELETED()" - все равно показывает удаленные записи ?

Pasha: Проверил - вроде как с этим флагом все нормально, он учитывается.

Andrey: Pasha пишет: Проверил - вроде как с этим флагом все нормально, он учитывается. Вот тестовый пример на хХарборе. http://files.mail.ru/32A93B73CC8F40BE900F5E889C5E7711 При первом запуске программы создаются базы в папке проекта DBF и файл пути к базе DBF_search.path Базы можно перекинуть на сервер и поменяв путь в DBF_search.path - тестировать скорость по сети. Хотя реальные тесты показывают совсем другое время. При работе нескольких программ в сети скорость LOCATE с 3 секунд может увеличиться до 3х минут. SET FILTER тоже не подарок... Условие ".AND.!DELETED()" - не учитывается в SET FILTER, LOCATE, dbfEval() Может строка поиска большая ?

Dima: Andrey [pre2] Subsystem Call ....: DBFCDX System Code .......: 1004 Default Status ....: .T. Description .......: Ошибка создания Operation .........: Arguments .........: Involved File .....: C:\1\555\dd\6\1\DBF\TestDogovor.dbf Dos Error Code ....: 3 Trace Through: ---------------- DBCREATE : 0 in Module: CREATE_TEST_DBF : 235 in Module: OPENDBFDIC.PRG MYOPENDBF : 18 in Module: OPENDBFDIC.PRG MAIN : 31 in Module: DBF_SEARCH.PRG [/pre2]

Andrey: Dima пишет: C:\1\555\dd\6\1\DBF\TestDogovor.dbf Сделай путь покороче, типа D:\DBF-Search Точно вылетает... Буду смотреть...

Dima: Andrey я вообще руками ни чего не делал и просто распаковал в эту папку и запустил EXE Могу понять что могло заглючить если бы папка была кириллицей названа.

Pasha: Andrey пишет: Условие ".AND.!DELETED()" - не учитывается в SET FILTER, LOCATE, dbfEval() Все упомянутые средства работают правильно, это неправильное условие поиска. Сколько будет дважды два .t. .or. .t. .and. .f. ? Подсказка: правильно будет (.t. .or. .t.) .and. .f.

Pasha: Dima пишет: я вообще руками ни чего не делал и просто распаковал в эту папку и запустил EXE там ручками надо создать папку dbf

Andrey: Pasha пишет: Подсказка: правильно будет (.t. .or. .t.) .and. .f. Спасибо БОЛЬШОЕ ! Вечно торопливость мешает правильно делать... А когда сделаешь, уже считаешь что всё правильно ! Исправленный пример - http://files.mail.ru/97F319C31C944A199D7AA97DA0136E7A SET FILTER - при первом запуске хорошо тормозит, 15 сек. поиска на локальной машине.... А что будет с ним на сервере, я даже не представляю. Dima - модуль FindBMDBFCDX.prg тебя ждет !

Dima: Andrey пишет: Вечно торопливость мешает правильно делать... Это точно [pre2] -------------------- Internal Error Handling Information --------------------- Subsystem Call ....: DBFCDX System Code .......: 1004 Default Status ....: .T. Description .......: Ошибка создания Operation .........: Arguments .........: Involved File .....: D:\DBF-Search\DBF\TestDogovor.dbf Dos Error Code ....: 3 Trace Through: ---------------- DBCREATE : 0 in Module: CREATE_TEST_DBF : 235 in Module: OPENDBFDIC.PRG MYOPENDBF : 18 in Module: OPENDBFDIC.PRG MAIN : 31 in Module: DBF_SEARCH.PRG [/pre2] Andrey пишет: Dima - модуль FindBMDBFCDX.prg тебя ждет ! А чего ? Мало примера что я дал ? Принцип тот же , выбираем в массив удовлетворяющие записи. Но поиск происходит по индексам (при чем по каждому такому полю нужно иметь индекс). ЗЫ Сел бы и разобрался без спешки и вопросов бы не было , впрочем их и не было даже после того как я показал самодостаточный пример и полагал что все ясно. В Xharbour в тестах вроде же есть пример skipeval.prg я его просто чуть модифицировал.

Andrey: Dima пишет: Description .......: Ошибка создания Operation .........: Arguments .........: Involved File .....: D:\DBF-Search\DBF\TestDogovor.dbf Dos Error Code ....: 3 А точно пробовал последний пример - DBF-Search2.7z ? У меня теперь в любой папке создает базу... Пробовал так D:\TEMP\1\TEST\DBF Не забыть удалить файл dbf_search.path если папки переименовал.

Dima: Andrey Да я сделал как в прошлый раз распаковал архив в отдельную папку и запустил EXE и выпал на эту ошибку. Искать ошибку лень да и Xharbour у меня нет что бы пересобрать.

Andrey: Dima пишет: Да я сделал как в прошлый раз распаковал архив в отдельную папку и запустил EXE Удали файл dbf_search.path, я его случайно в архив поместил. Andrey пишет: При первом запуске программы создаются базы в папке проекта DBF и файл пути к базе DBF_search.path Базы можно перекинуть на сервер и поменяв путь в DBF_search.path - тестировать скорость по сети.



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