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





Пост 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: 3097
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 18.11.13 17:57. Заголовок: Какое решение самое ..


Какое решение самое лучшее для БЫСТРОГО поиска по различным полям без открытых индексов ?
Решение Pasha или
Dima пишет:

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



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




Пост N: 3723
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 18.11.13 18:05. Заголовок: Andrey Берешь базу ..


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

PS
Ответь мне на ЛС

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




Пост N: 3098
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 18.11.13 18:13. Заголовок: Dima пишет: Берешь ..


Dima пишет:

 цитата:
Берешь базу на пару-тройку лимонов записей и делаешь 2 теста и смотришь что быстрее.


На ЛС ответил.
Помоги сделать эти тесты ? Ну очень интересно... Всем тоже узнать хочется !!!
А я что нибудь другое сваяю для тебя ?

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




Пост N: 3724
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 18.11.13 18:18. Заголовок: Andrey Давай мне ба..


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

или

Опиши структуру базы , чем заполнять и что будем искать.

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




Пост N: 3099
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 18.11.13 19:26. Заголовок: Хорошо, делаю...


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

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


Пост N: 130
Зарегистрирован: 29.05.10
ссылка на сообщение  Отправлено: 19.11.13 11:06. Заголовок: Andrey пишет: Какое..


Andrey пишет:

 цитата:
Какое решение самое лучшее для БЫСТРОГО поиска по различным полям без открытых индексов ?
Решение Pasha или
Dima пишет:


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

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




Пост N: 3043
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 20.11.13 10:58. Заголовок: Andrey пишет: Хорош..


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 сек. (разница чувствуется)


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




Пост N: 3102
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 20.11.13 11:50. Заголовок: Pasha БОЛЬШОЕ спасиб..


Pasha БОЛЬШОЕ спасибо за тесты.
Я свою заготовку переслал Диме. У меня там замороченей тест получается... В смысле много полей ищется сразу в базе.

Можешь ли выложить свой исходник теста ?
Хочется посмотреть код профессионала.
Заранее спасибо.

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




Пост N: 3044
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 20.11.13 12:23. Заголовок: Такая большая пробле..


Такая большая проблема сделать простейший тест, что ли ?
Вот код:

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



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




Пост N: 3046
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 20.11.13 14:22. Заголовок: Можно классифицирова..


Можно классифицировать скорость выборки на 3 уровня:

1. При монопольном доступе к файлу, во время индексации, и в только что написанной функции dbEvalDirect
Скорость максимальная, так как ресурсы расходуются только на чтение исходного файла, и больше ни на что.
При этом для монопольного доступа возможно чтение любого фрагмента файла с управляющим индексом или без него.
С индексом скорость будет немного хуже.
Для индексации и dbEvalDirect считывается весь файл.
Поскольку letodb открывает файлы монопольно, то на него не влияют факторы, описанные ниже.

2. Для файла, открытого в режиме shared без управляющего индекса. Скорость в несколько раз хуже за счет того,
что при чтении каждой записи обновляется reccount.

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


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




Пост N: 3103
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 20.11.13 14:23. Заголовок: А как отобразить ото..


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



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




Пост N: 3728
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 20.11.13 14:29. Заголовок: Andrey BM фильтр я ..


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

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




Пост N: 3105
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 20.11.13 14:38. Заголовок: Dima пишет: BM филь..


Dima пишет:

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


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

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




Пост N: 3729
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 20.11.13 14:44. Заголовок: Без BM будет не опти..


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


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




Пост N: 3047
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 20.11.13 14:59. Заголовок: Andrey пишет: А как..


Andrey пишет:

 цитата:
А как отобразить отобранные записи в BROWSE() ?



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

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




Пост N: 3109
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 21.11.13 21:53. Заголовок: Pasha пишет: Сделат..


Pasha пишет:

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


А по другому никак ? Сложновато получается... Или мне кажется только ?
Минимальный код для такого BROWSE() привести можете ?

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




Пост N: 3730
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 21.11.13 22:01. Заголовок: Andrey Похоже читае..


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

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




Пост N: 3110
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 21.11.13 22:39. Заголовок: Dima пишет: Похоже ..


Dima пишет:

 цитата:
Похоже читаешь сообщения но ни чего не тестишь отсюда и не понятки.


Делаю. На этой неделе выложу.

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





Пост N: 379
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 22.11.13 21:09. Заголовок: Andrey пишет: А как..


Andrey пишет:

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



Со времен Clipper, когда нужных записей в большой таблице мало - выяснил, что гораздо эффективнее их считать в массив, а потом только их и показывать. Примерно так:
 
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)


где:
Скрытый текст



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




Пост N: 3111
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 23.11.13 19:33. Заголовок: Dima пишет: Похоже ..


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

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

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