Автор | Сообщение |
|
| постоянный участник
|
Пост N: 1585
Зарегистрирован: 12.09.06
|
|
Отправлено: 07.12.10 13:32. Заголовок: Как правильно сделаь выборку по индексу ?
Всем привет. Наконец то дошли руки до оптимизации, но как сделать не знаю. Имеется большая база (500тыс. записей и более) поступивших платежей от жителей. Раз в месяц эти поступившие платежи перекидываются в другую базу. Запись которая уже успешно обработана (т.е. перекинута в другую базу) помечается ( ну допустим в поле NCALC записывается 1 ) ! Чтоб не просматривать всегда всю базу, я раньше пробовал делать условную индексацию всей БД с условиями "NCALC < 1 .AND. DELETED()==.F." Но при обработке записи, когда записываешь в поле NCALC = 1, происходит вылет с ошибкой. Уже не помню какой. Приходиться сейчас ВСЕГДА перелопачивать ВСЮ базу, типа: do while !EOF() IF NCALC <1 // моя обработка ENDIF skip enddo Это медленно, даже если просто пропускаешь запись.... Подскажите как этого избежать ! Или другие алгоритмы...
|
|
|
Ответов - 17
[только новые]
|
|
|
| постоянный участник
|
Пост N: 55
Зарегистрирован: 29.05.06
|
|
Отправлено: 07.12.10 16:47. Заголовок: Думаю, это происходи..
Думаю, это происходит потому, что текущая обрабатываемая запись при записи NCALC := 1 выходит из индекса, по которому идёт переборка. И следующий skip делается от записи, которая фактически индексу не принадлежит... Попробуйте так dbgotop() do while ! eof() // Пока есть хоть одна соответствующая условному индексу ( необработанная ) запись // обработка , в результате чего первая запись в индексе ВЫЧЁРКИВАЕТСЯ из списка... dbgotop() // Идём на запись, которая стала первой в индексе в результате вычёркивания предыдущей enddo Или так do while .T. dbgotop() if eof() exit endif // Обработка enddo
|
|
|
|
| |
Пост N: 171
Зарегистрирован: 12.11.06
|
|
Отправлено: 07.12.10 20:27. Заголовок: Может опять, чего-то..
Может опять, чего-то не допонял... Делаем индексный файл(индекс): name_ind into ncalc Активируем его, например DbSetOrder(x) DbGoTop() do whil ncalc < 1 операторы endd
|
|
|
|
| постоянный участник
|
Пост N: 1006
Зарегистрирован: 09.10.06
|
|
Отправлено: 07.12.10 20:50. Заголовок: Andrey пишет: когда..
Andrey пишет: цитата: | когда записываешь в поле NCALC = 1, происходит вылет с ошибкой. |
| И что вы пытаетесь записать в числовое поле ? Подсказка: цитата: | PROCEDURE main() LOCAL NCALC ? ValType( NCALC = 1 ) ? ValType( NCALC := 1 ) RETURN |
| И еще ! DELETED() смотрится лучше, чем DELETED() == .F.
|
|
|
|
| постоянный участник
|
Пост N: 1586
Зарегистрирован: 12.09.06
|
|
Отправлено: 07.12.10 21:04. Заголовок: Петр пишет: И что в..
Петр пишет: цитата: | И что вы пытаетесь записать в числовое поле ? Подсказка: |
| Ошибся в написании, конечно же FIELD->NCALC := 1 ! Петр пишет: цитата: | И еще ! DELETED() смотрится лучше, чем DELETED() == .F. |
| Учту.
|
|
|
|
| постоянный участник
|
Пост N: 1587
Зарегистрирован: 12.09.06
|
|
Отправлено: 07.12.10 21:10. Заголовок: AndreyZh пишет: DbG..
AndreyZh пишет: цитата: | DbGoTop() do whil ncalc < 1 операторы enddо |
| Да вылетит это. Не правильно написано просто ! DbGoTop() do while FIELD->NCALC < 1 // проверка записи в другую базу // если все нормально, то пишем в поле FIELD->NCALC := 1 ! FIELD->NCALC := 1 skip enddo
|
|
|
|
| постоянный участник
|
Пост N: 1007
Зарегистрирован: 09.10.06
|
|
Отправлено: 07.12.10 21:26. Заголовок: Ваш код и код ошибки..
Ваш код и код ошибки в студию. А то разговор ни о чем получается. Если у вас есть индех, то правильное использование DbEval всегда быстрее выполняется чем do while enddo
|
|
|
|
| |
Пост N: 172
Зарегистрирован: 12.11.06
|
|
Отправлено: 07.12.10 22:10. Заголовок: Сейчас проверил код ..
Сейчас проверил код на Clipper, замещая ключевое поле. У Вас должно сработать DbGoTop() do while FIELD->NCALC < 1 // проверка записи в другую базу // если все нормально, то пишем в поле FIELD->NCALC := 1 ! FIELD->NCALC := 1 skip enddo
|
|
|
|
| постоянный участник
|
Пост N: 1588
Зарегистрирован: 12.09.06
|
|
Отправлено: 07.12.10 22:26. Заголовок: G-Serge пишет: Дума..
G-Serge пишет: цитата: | Думаю, это происходит потому, что текущая обрабатываемая запись при записи NCALC := 1 выходит из индекса, по которому идёт переборка. И следующий skip делается от записи, которая фактически индексу не принадлежит... |
| Я так же думал, но не знал как побороть ! Сделал тестовый пример, он не вылетает. Вспомнил, что на Клипере 5.3 делал такое, так вот он вылетал. Сделал на хХарборе, не вылетает, но и правильно все записи не обрабатывает. Смотрите тестовый пример: http://files.mail.ru/8SNB81<\/u><\/a> Кто может подсказать правильное решение ? Заместо 1 записываю 50. Но это не важно.
|
|
|
|
| |
Пост N: 173
Зарегистрирован: 12.11.06
|
|
Отправлено: 07.12.10 22:45. Заголовок: Вы делаете условную ..
Вы делаете условную индексацию "plata", да потом в ней еще меняете значение ключевого поля, сканируя все виды индексов этого файла... Увы это выше уровня моего понимания Когда приводил и тестил пример у меня был ключевой индекс (который заменял) и делал "прямой" скан таблицы
|
|
|
|
| постоянный участник
|
Пост N: 1589
Зарегистрирован: 12.09.06
|
|
Отправлено: 07.12.10 22:59. Заголовок: AndreyZh пишет: Увы..
AndreyZh пишет: цитата: | Увы это выше уровня моего понимания |
| Так я и писал, что такое делал раньше. А если переделать на ваш вариант ? Что получиться и как будет работать ?
|
|
|
|
| постоянный участник
|
Пост N: 56
Зарегистрирован: 29.05.06
|
|
Отправлено: 07.12.10 23:01. Заголовок: Что, вот такой вариа..
Что, вот такой вариант неправильно работает ? do while .T. dbgotop() // Идём на первую запись с NCALC == 0 if eof() // Если нет записей с NCALC == 0 exit endif NCALC := 1 // Вычёркиваем enddo Тогда во так... do while .T. If ! PLATA->(dbseek(0)) // Ищем запись с NCALC==0 // Если не нашли - выходим exit endif NCALC := 1 // Вычёркиваем enddo И не надо без лишней необходимости к индексам по условию прибегать, я думаю...
|
|
|
|
|
| Администратор
|
Пост N: 1707
Зарегистрирован: 23.05.05
|
|
Отправлено: 07.12.10 23:28. Заголовок: Насколько я понял, з..
Насколько я понял, задача сводится к циклу по значению индексного поля xOld с присвоением ему значения xNew. Условный индекс или нет - несущественно. Предлагаю 2 варинта решения: Вариант 1 while dbSeek(xOld) ... (обработка) Field->FName := xNew enddo Вариант 2 aRecs := {} dbSeek(xOld) while FName = xOld ... (обработка) AADD(aRecs, RecNo()) skip enddo AEval(aRecs, {|n| dbGoto(n), Field->FName := xNew}) Блокировки, сворачивание цикла через dbEval, соль и пряности добавить по вкусу. По скорости второй вариант даже предпочтительнее, поскольку множественный seek будет выполняться медленнее, чем простой цикл, и затем цикл с goto
|
|
|
|
| постоянный участник
|
Пост N: 1590
Зарегистрирован: 12.09.06
|
|
Отправлено: 08.12.10 15:51. Заголовок: Pasha пишет: По ско..
Pasha пишет: цитата: | По скорости второй вариант даже предпочтительнее, поскольку множественный seek будет выполняться медленнее, чем простой цикл, и затем цикл с goto |
| Вот это интересно ! Я даже и не подымал о такой простой вещи - создать массив нужных записей обработки ! А время на создание массива много будет тратиться ? С учетом если примерно 50-90 тыс.записей нужно обрабатывать ежемесячно ? А что будет быстрей работать ? AEval(aRecs, {|n| dbGoto(n), Field->FName := xNew}) или FOR nI:=1 TO LEN(aRecs) dbGoto(aRecs[nI]) // Бегунок // Обработка (запись в другую БД) NEXT
|
|
|
|
| постоянный участник
|
Пост N: 57
Зарегистрирован: 29.05.06
|
|
Отправлено: 08.12.10 19:26. Заголовок: А какой размер масси..
А какой размер массива максимальный, кстати ?
|
|
|
|
| Администратор
|
Пост N: 1708
Зарегистрирован: 23.05.05
|
|
Отправлено: 08.12.10 19:30. Заголовок: Быстрее всего будет ..
Быстрее всего будет работать FOR each nI in aRecs) dbGoto(nI) // Бегунок // Обработка (запись в другую БД) NEXT Поскольку при выполнении блока кода в aeval vm harbour запускается еще раз для каждого элемента массива Что касается заполнения массива - думаю, время будет приемлемым достаточно сделать тест: nSec := Seconds() for nI := 1 to 100000 AADD(aRecs, nI) next ? Seconds() - nSec Слабое место в таком алгоритме то, что если программа в первом цикле обработки вдруг споткнется на ровном месте аварийно завершится, то второй цикл выполнен не будет
|
|
|
|
| |
Пост N: 174
Зарегистрирован: 12.11.06
|
|
Отправлено: 08.12.10 20:39. Заголовок: G-Serge пишет: А ка..
G-Serge пишет: цитата: | А какой размер массива максимальный, кстати ? |
| Определяется размером доступной памяти - сдуру решил перепроверить на 20Gb прервал.
|
|
|
|
| |
Пост N: 90
Зарегистрирован: 04.12.07
|
|
Отправлено: 09.12.10 13:21. Заголовок: // По условному инде..
// По условному индексу do while .T. dbgotop() do while ! eof() if FIELD->NCALC = 0 FIELD->NCALC := 1 // Запись выпадает из условного индекса // Последовательность обработки по индексу сбивается // Необходимо начинать всё сначала exit endif enddo if eof() exit endif enddo
|
|
|
|