Автор | Сообщение |
|
| |
Пост 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... напрягает....
|
|
|
Ответов - 120
, стр:
1
2
3
4
5
6
All
[только новые]
|
|
|
| постоянный участник
|
Пост N: 3097
Зарегистрирован: 12.09.06
|
|
Отправлено: 18.11.13 17:57. Заголовок: Какое решение самое ..
Какое решение самое лучшее для БЫСТРОГО поиска по различным полям без открытых индексов ? Решение Pasha или Dima пишет: цитата: | Вариант конечно когда нет подходящего индекса а если есть то быстрее будет конечно через dborderinfo(DBOI_SKIPREGEX,,,cRegex) |
|
|
|
|
|
| |
Пост N: 3723
Зарегистрирован: 17.05.05
|
|
Отправлено: 18.11.13 18:05. Заголовок: Andrey Берешь базу ..
Andrey Берешь базу на пару-тройку лимонов записей и делаешь 2 теста и смотришь что быстрее. PS Ответь мне на ЛС
|
|
|
|
| постоянный участник
|
Пост N: 3098
Зарегистрирован: 12.09.06
|
|
Отправлено: 18.11.13 18:13. Заголовок: Dima пишет: Берешь ..
Dima пишет: цитата: | Берешь базу на пару-тройку лимонов записей и делаешь 2 теста и смотришь что быстрее. |
| На ЛС ответил. Помоги сделать эти тесты ? Ну очень интересно... Всем тоже узнать хочется !!! А я что нибудь другое сваяю для тебя ?
|
|
|
|
| |
Пост N: 3724
Зарегистрирован: 17.05.05
|
|
Отправлено: 18.11.13 18:18. Заголовок: Andrey Давай мне ба..
Andrey Давай мне базу да побольше и условия фильтрации (для начала хватит по одному-двум полям) или Опиши структуру базы , чем заполнять и что будем искать.
|
|
|
|
| постоянный участник
|
Пост N: 3099
Зарегистрирован: 12.09.06
|
|
Отправлено: 18.11.13 19:26. Заголовок: Хорошо, делаю...
Хорошо, делаю.
|
|
|
|
| постоянный участник
|
Пост N: 130
Зарегистрирован: 29.05.10
|
|
Отправлено: 19.11.13 11:06. Заголовок: Andrey пишет: Какое..
Andrey пишет: цитата: | Какое решение самое лучшее для БЫСТРОГО поиска по различным полям без открытых индексов ? Решение Pasha или Dima пишет: |
| Если воообще без индексов , то Locate :) Но и тут надо уточнить- "дикий" поиск или точный. Будет ли продолжение ( добавление следующих условий ) или "начни с начала" :))) Каждая задача имеет свое конкретное решение и сравнивать их нет смысла
|
|
|
|
| Администратор
|
Пост 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 сек. (разница чувствуется)
|
|
|
|
| постоянный участник
|
Пост N: 3102
Зарегистрирован: 12.09.06
|
|
Отправлено: 20.11.13 11:50. Заголовок: Pasha БОЛЬШОЕ спасиб..
Pasha БОЛЬШОЕ спасибо за тесты. Я свою заготовку переслал Диме. У меня там замороченей тест получается... В смысле много полей ищется сразу в базе. Можешь ли выложить свой исходник теста ? Хочется посмотреть код профессионала. Заранее спасибо.
|
|
|
|
| Администратор
|
Пост 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
|
|
|
|
| Администратор
|
Пост 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.) перед выборкой. Еще причина - выборка записи по ключу в самом индексе, т.е. чтение индекса.
|
|
|
|
| постоянный участник
|
Пост N: 3103
Зарегистрирован: 12.09.06
|
|
Отправлено: 20.11.13 14:23. Заголовок: А как отобразить ото..
А как отобразить отобранные записи в BROWSE() ? Я сталкивался с такой задачей, т.е. есть в массиве номера записей (полученные из поиска) которые нужно отобразить на экране. Как в таком случае поступают (с учетом работы в будущем не LetoDB) ?
|
|
|
|
|
| |
Пост N: 3728
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.11.13 14:29. Заголовок: Andrey BM фильтр я ..
Andrey BM фильтр (затем browse) я же пример приводил выше
|
|
|
|
| постоянный участник
|
Пост N: 3105
Зарегистрирован: 12.09.06
|
|
Отправлено: 20.11.13 14:38. Заголовок: Dima пишет: BM филь..
Dima пишет: цитата: | BM фильтр (затем browse) я же пример приводил выше |
| А без BM фильтра ? Я у себя давно делал поиск по подчиненной базе. Приходилось при поиске в доп.поле записывать 0, а при нахождении 1, а потом показывать записи с кодом=1 . Это не оптимально. Вот и хочу понять как такие вещи делать ?
|
|
|
|
| |
Пост N: 3729
Зарегистрирован: 17.05.05
|
|
Отправлено: 20.11.13 14:44. Заголовок: Без BM будет не опти..
Без BM будет не оптимально. Как вариант складывать можно выбранные записи во временную базу Или переделать Skipper что бы он ходил по массиву с номерами записей
|
|
|
|
| Администратор
|
Пост N: 3047
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.11.13 14:59. Заголовок: Andrey пишет: А как..
Andrey пишет: цитата: | А как отобразить отобранные записи в BROWSE() ? |
| Сделать источником данных для browse не р/о, а массив. В массив загонять те данные, которые надо выдать, плюс номер записи. После выбора нужной строки массива делать dbGoto() по номеру выбранной записи из строки массива.
|
|
|
|
| постоянный участник
|
Пост N: 3109
Зарегистрирован: 12.09.06
|
|
Отправлено: 21.11.13 21:53. Заголовок: Pasha пишет: Сделат..
Pasha пишет: цитата: | Сделать источником данных для browse не р/о, а массив. В массив загонять те данные, которые надо выдать, плюс номер записи. После выбора нужной строки массива делать dbGoto() по номеру выбранной записи из строки массива. |
| А по другому никак ? Сложновато получается... Или мне кажется только ? Минимальный код для такого BROWSE() привести можете ?
|
|
|
|
| |
Пост N: 3730
Зарегистрирован: 17.05.05
|
|
Отправлено: 21.11.13 22:01. Заголовок: Andrey Похоже читае..
Andrey Похоже читаешь сообщения но ни чего не тестишь отсюда и не понятки. Сделай простейший пример с BM фильтром и все станет ясно. Что касается Browse то он у каждого свой под свои задачи и в любом из них есть Skipper или аналог вот его и нужно переделать если что.
|
|
|
|
| постоянный участник
|
Пост N: 3110
Зарегистрирован: 12.09.06
|
|
Отправлено: 21.11.13 22:39. Заголовок: Dima пишет: Похоже ..
Dima пишет: цитата: | Похоже читаешь сообщения но ни чего не тестишь отсюда и не понятки. |
| Делаю. На этой неделе выложу.
|
|
|
|
| |
Пост 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) где: Скрытый текст
* ------------------------------------------------ * 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 * ----------------------------- *
|
|
|
|
|
| постоянный участник
|
Пост 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 пишет: Жду от Димы. Вообще кто, что можете порекомендовать, пишите. Я не смотря на долгую работу с Клипером, всех тонкостей не знаю. Сам проект на хХарборе 1.2.3 http://files.mail.ru/5D8A880F51054F7BBB3A279FB1E279EA
|
|
|
Ответов - 120
, стр:
1
2
3
4
5
6
All
[только новые]
|
|