On-line: гостей 1. Всего: 1 [подробнее..]
АвторСообщение





Пост N: 368
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 08.11.13 13:41. Заголовок: DBFNTX: как грамотно прервать работу SET FILTER ?


Добрый день

Есть некая таблица:
date D8
idx1 N5
idx2 N5
flags C5
string C80

И есть фрагмент программы:
filter_sx := "" 
SELE table
SET FILT TO IIF(LEN(filter_sx)==0,TRUE,(filter_sx $ table->str))
DBEDIT(...)

Т.е. пока в строку фильтра ничего не попало - видны все записи.
Если юзер хочет отфильтровать часть записей по содержимому строки - срабатывает фильтр.

Возникает ситуация: если таблица большая (>100 тыс записей), расположена на сервере и юзер желает увидеть какие-то "редкие" записи, процесс фильтрации начинает занимать непозволительно долгое время. Юзер понимает, что лучше набрать в фильтре что-то другое, но как остановить процесс текущей фильтрации ?

Делал так:
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

Но данный метод приводит вообще к чудным результатам: в 90% случаев после нажатия Esc - DBEDIT() начинает бешено прокручивать список вверх и зависает на первом элементе таблицы. Насколько понял по отладчику, что-то непонятное (для меня) происходит в недрах объекта в районе :Stabilize()

С какой стороны к этому вопросу подступиться?

PS: в Clipper было тоже самое - но когда тормозило всё, это было не так заметно, а сейчас, на фоне быстрой и адекватной работы Harbour... напрягает....

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 120 , стр: 1 2 3 4 5 6 All [только новые]


администратор




Пост N: 3706
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 10.11.13 15:20. Заголовок: Sergy пишет: ProcSt..


Sergy пишет:

 цитата:
ProcStack()


Самопал или либа нужна какая ?

Вероятно самопал что то типа
 
FUNC ProcStack()

LOCAL n := 0
Local ret:=""

WHILE ! Empty( ProcName( n ) )
ret+=" "+ProcName( n++ )
ENDDO

RETURN ret



Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3075
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 10.11.13 15:47. Заголовок: Dima Есть в базе по..


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

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 3707
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 10.11.13 15:59. Заголовок: Заготовку не накидаю..


Заготовку не накидаю а вот идея как бы есть (развивай)
Да держим по каждому полю индекс что бы быстро отобрать нужные записи (но это дело вкуса)
Переключаемся на первый поисковый индекс и ищем как я выше описывал в примере.
Отобрали подходящие записи в массив и установили BM фильтр. Переключаемся на второй
поисковый индекс и повторяем процедуру поиска по этому полю собрав подходящие записи
в массив. Снимаем BM фильтр (вероятно можно и не снимать) и ставим новый и так далее. Теоретически должно работать быстро.
Чем дальше тем меньше записей будет попадать в обработку.

Пример
 
#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



Вот такую функцию можно сделать
 
//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



Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 136
Зарегистрирован: 19.05.05
ссылка на сообщение  Отправлено: 10.11.13 16:54. Заголовок: Для этого лучше орга..


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


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 376
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 10.11.13 17:54. Заголовок: Dima пишет: Самопал..


Dima пишет:

 цитата:
Самопал или либа нужна какая ?


 * ---------------------------------------- * 
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
* ---------------------------------------- *

Удобно в некоторых случаях делать например так: ProcStack(,,TRUE,CRLF) или просто ProcStack()

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник


Пост N: 126
Зарегистрирован: 29.05.10
ссылка на сообщение  Отправлено: 11.11.13 13:20. Заголовок: Sergy пишет: Один ю..


Sergy пишет:

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

Перестраивать индекс каждый раз?


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

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3076
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 11.11.13 15:47. Заголовок: ММК пишет: Нет. Мен..


ММК пишет:

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


Ага. Я это имел в виду.

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 3708
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 11.11.13 16:16. Заголовок: Andrey Так хотел пр..


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

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3077
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 11.11.13 19:40. Заголовок: Dima пишет: или не ..


Dima пишет:

 цитата:
или не юзал ?


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

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 377
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 17.11.13 19:04. Заголовок: ММК пишет: Нет. Мен..


ММК пишет:

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


Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно).


Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3094
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 17.11.13 20:01. Заголовок: Sergy пишет: Ну вед..


Sergy пишет:

 цитата:
Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно).


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


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 68
Зарегистрирован: 17.10.05
ссылка на сообщение  Отправлено: 18.11.13 13:33. Заголовок: Andrey пишет: Ну ве..


Andrey пишет:

 цитата:
Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно).


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

Спасибо: 0 
ПрофильЦитата Ответить
moderator


Пост N: 718
Зарегистрирован: 06.07.06
ссылка на сообщение  Отправлено: 18.11.13 14:43. Заголовок: LYSK пишет: существ..


LYSK пишет:

 цитата:
существовала такая приблуда, которая называлась SUBINDEX.


Это была одна из фичей Six3. В Harbour это тоже есть, сам, правда, не пробовал.

Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 3040
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 18.11.13 15:07. Заголовок: Andrey пишет: Повер..


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*)
Какие есть еще подводные камни - надо подумать, так как я эту функцию сделал спонтанно, как только появилась такая идея.


Спасибо: 1 
ПрофильЦитата Ответить
администратор




Пост N: 3720
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 18.11.13 15:20. Заголовок: Pasha пишет: dbEval..


Pasha пишет:

 цитата:
dbEvalDirect(bDo, bFilter)


Вариант конечно когда нет подходящего индекса а если есть то быстрее будет конечно через dborderinfo(DBOI_SKIPREGEX,,,cRegex)
сделать выборку.

PS
Примерчик выше

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 378
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 18.11.13 15:27. Заголовок: Pasha пишет: Исполь..


Pasha пишет:

 цитата:
Использование индекса с условием for - это некрасивое решение, поскольку для поиска формируется ненужный разовый индекс, при создании которого идет выборка всего файла.


Согласен с этим. Поскольку при таком подходе из всех возможных вариантов будет использован наиболее медленный, с перечитыванием всего файла с начала и до конца. Банальный SET FILTER так будет себя вести только в том случае, если удовлетворяющих записей меньше, чем строк DBEDIT() на экране. Во всех остальных случаях он будет быстрее.


 цитата:
Вот эта маленькая функция: http://zalil.ru/34818847
Использование функции:
dbEvalDirect(bDo, bFilter)
Смысл параметров такой же, как и в dbEval()


Спасибо, изучу.

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник


Пост N: 128
Зарегистрирован: 29.05.10
ссылка на сообщение  Отправлено: 18.11.13 15:30. Заголовок: LYSK пишет: Ну ведь..


LYSK пишет:

 цитата:
Ну ведь для того, чтобы перестроить индекс (даже локально) - нужно перечитать все записи, хранящиеся на сервере (удаленно).


LYSK пишет:

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


Т.е. необходимо и достаточно наличие хотя бы одного индекса, на основе которого и происходят все последующие выборки.
Вот, например , сырье .Индекс по наименованию. Выбираем ( правой кл. мыши ) поле "остаток на нач.дня" равное нулю ( или вводим любое нужное значение )


Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 3041
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 18.11.13 15:31. Заголовок: Sergy пишет: Спас..


Sergy пишет:

 цитата:


Спасибо, изучу.



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

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник


Пост N: 129
Зарегистрирован: 29.05.10
ссылка на сообщение  Отправлено: 18.11.13 15:35. Заголовок: В этой выборке меня ..


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

Это можно делать в любой последовательности для любого кол-вы полей


Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 3042
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 18.11.13 17:05. Заголовок: Pasha пишет: Какие ..


Pasha пишет:

 цитата:
Какие есть еще подводные камни - надо подумать,



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

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 120 , стр: 1 2 3 4 5 6 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 465
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет