Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Как ускорить этот цикл? (выборка из архивных файлов по условию) / 21 сообщений из 21, страница 1 из 1
26.03.2010, 09:57
    #36543804
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
Привет всем. Есть код, смысл его в том, что есть архивные файлы с оплатой, они находятся в папках для каждого месяца, а месяца разбиты по годам (но это не важно).
дерево такое:
2008
_01\oplata.dbf
_02\oplata.dbf
_03\oplata.dbf
_NN\oplata.dbf
2009
_01\oplata.dbf
_02\oplata.dbf
_03\oplata.dbf
_NN\oplata.dbf
Задача в курсор выбрать из всех таблиц записи по лицевому счету.
Написал цикл выборки, работает отлично, но во многопользовательском режиме тормозит.
Использую SET KEY на каждой таблице, а потом перебором записей вставляю их в курсор. APPEND FROM добавляет намного медленней. SELECT * - тоже не вариант - вообще глохнет надолго.
Можно ли еще ускорить этот процесс, может есть способы это делать быстрее, чем в приведенном коде?

автор
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
CREATE CURSOR cTemp (DATE D, summa N(13,2))
ADIR(dir,'arhiv\*.*',"D") 
FOR n=1 TO ALEN(dir,1)
	IF AT('D',dir(n,5))>0 AND VAL(dir(n,1))>0
		cYear=dir(n,1)
		FOR nn=1 TO 12
			cMon=PADL(ALLTRIM(STR(nn)),2,'0')
			cPath=CURDIR()+'arhiv\'+cYear+'\'+cMon+'\'
			IF DIRECTORY(cPath)
				cFile=cPath+'oplata.dbf'
				IF FILE(cFile)
					SELECT 0
					USE &cFile ALIAS tmp SHARED
					SET ORDER TO tag id_ls
					SET KEY TO nlsz
					SCAN
						SCATTER TO eee
						SELECT cTemp
						APPEND BLANK
						GATHER FROM eee
					ENDSCAN
					USE IN tmp
				ENDIF
			ENDIF
		ENDFOR
	ENDIF
ENDFOR
...
Рейтинг: 0 / 0
26.03.2010, 10:24
    #36543870
tanglir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
А. С.,

Как получивший подобное наследство заявляю: если есть хоть какая-то возможность, спихни все эти файлы оплат в одну табличку на sql-сервер (только добавь поле "дата" :) ), добавь индекс по ЛС, и выбирай с хорошей скоростью и без этих ублюдочных циклов...
...
Рейтинг: 0 / 0
26.03.2010, 10:32
    #36543892
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
sql сервер не вариант, спихнуть в одну таблицу хорошая идея, только таблица разрастется. Как вариант можно одну таблицу вести для каждого года.
Я хотел спросить можно ли сделать выборку быстрее при данных обстоятельствах?
...
Рейтинг: 0 / 0
26.03.2010, 11:58
    #36544160
karly™
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
1. Какая версия фокса? В VFP9 запросы стали работать намного быстрее.

2. Приведи пример запроса, который "глохнет надолго". Наверняка его можно оптимизировать, и добавлять данные не построчно, а "пачкой"

3. Вместо конструкции "Append Blank + Gather From" можно добавлять данные одной командой Insert from memvar

4. Обработка одной большой таблицы будет быстрее, чем нескольких маленьких. Если данные архивные, то нет проблем создать слить все в одну таблицу
...
Рейтинг: 0 / 0
26.03.2010, 12:15
    #36544236
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
karly™1. Какая версия фокса? В VFP9 запросы стали работать намного быстрее.
Простите, 9-ка

karly™2. Приведи пример запроса, который "глохнет надолго". Наверняка его можно оптимизировать, и добавлять данные не построчно, а "пачкой"
Если в цикле на каждой таблице делать
SELEST * FROM tmp INTO CURSOR ttt
а после из курсора вставлять APPEND FROM DBF('ttt')

karly™3. Вместо конструкции "Append Blank + Gather From" можно добавлять данные одной командой Insert from memvar
Спасибо, попробую, только думаю что это вряд-ли ускорит процесс. Я понимаю что у меня загвоздка с открытием самих таблиц, потому что быстрее чем SET KEY TO в моем случае вряд-ли что-то будет работать....

karly™4. Обработка одной большой таблицы будет быстрее, чем нескольких маленьких. Если данные архивные, то нет проблем создать слить все в одну таблицу
Просто у меня в программе все выборки и отчеты интерфейсно заточены под такое дерево. Придется много переделывать. Вот я и спрашваю как еще можно сделать именно для данного представления таблиц.
...
Рейтинг: 0 / 0
26.03.2010, 12:17
    #36544246
karly™
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
А. С.Если в цикле на каждой таблице делать
SELEST * FROM tmp INTO CURSOR ttt
а после из курсора вставлять APPEND FROM DBF('ttt')Условия запроса какие пишете? И какие есть индексы у таблиц?
...
Рейтинг: 0 / 0
26.03.2010, 12:51
    #36544400
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
nlsz=555
SELEST * FROM tmp WHERE id_ls=nlsz INTO CURSOR ttt

Индексы в таблицах *.CDX по id_ls присутствуют, но не вижу связи между SELECT * и индексами
...
Рейтинг: 0 / 0
26.03.2010, 12:54
    #36544407
Как ускорить этот цикл? (выборка из архивных файлов по условию)
А. С.не вижу связи между SELECT * и индексамиВот это и плохо ибо связь самая прямая. Наличие правильных индексов очень сильно ускоряет select.
...
Рейтинг: 0 / 0
26.03.2010, 13:06
    #36544449
karly™
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
Посмотрел на код внимательнее

1. Вместо макроподстановки USE &cFile ALIAS tmp SHARED лучше использовать именное выражение USE (cFile) ALIAS tmp SHARED

2. Связка
Код: plaintext
1.
2.
3.
SET ORDER TO tag id_ls
SET KEY TO nlsz
SCAN
- это медленно. Быстрее (и проще) одной командой
Код: plaintext
Scan for id_ls = nlsz
Это при условии, что индекс выглядит как Index on id_ls tag id_ls

3. Если индекс простой, то запрос в девятке должен работать с той же скоростью, что и поиск по индексу. Если это не так - переписывайте условие запроса, чтобы оно точно совпадало с индексным выражением, и сравнивайте Set("collate") и IDXCOLLATE(). Сделав через запрос, вы получите выигрыш в обработке сразу нескольких записей. Ну и теоретически неявное открытие таблиц запросом должно работать чуть быстрее, чем Use (cTable)

4. Медленное открытие таблиц на сервере можно побороть правильной настройкой сети. Кроме того, можно открывать таблицы заранее, при старте приложения, и держать их открытыми. Вы получите единовременное замедление в самом начале, которое окупится при многократном обращении к ним. Для подстаховки можно открывать их только на чтение - USE (cTable) Shared noupdate
...
Рейтинг: 0 / 0
26.03.2010, 13:06
    #36544452
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
Любой SELECT быстрее выборки SET KEY TO он не будет работать все равно. А таблицы при этом естесственно проиндексирваны.
А вот "Наличие правильных индексов очень сильно ускоряет select" - для меня откровение, нигде не встречал, почитаю.
...
Рейтинг: 0 / 0
26.03.2010, 13:23
    #36544501
karly™
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
При соблюдении следующих условий
1. VFP 9
2. Индексное выражение точно совпадает с условием запроса
3. Порядок сортировки индекса idxcollate() совпадает с настройкой set collate
3. Кодовая страница таблицы совпадает с cpCurrent()

Select будет работать с той же скоростью, что и поиск по индексу seek или Set key

Почитать, и выполнить сравнительные тесты вы можете здесь http://foxclub.ru/articles/art45.php#example

Напишите точное выражение индекса таблицы, и текст своего запроса, тогда можно будет найти причину замедления.
...
Рейтинг: 0 / 0
26.03.2010, 13:33
    #36544539
Как ускорить этот цикл? (выборка из архивных файлов по условию)
автор2. Связка

SET ORDER TO tag id_ls
SET KEY TO nlsz
SCAN

- это медленно. Быстрее (и проще) одной командой

Scan for id_ls = nlsz

ИМХО,

Код: plaintext
1.
2.
3.
4.
IF SEEK(nlsz)
  DO WHILE id_ls=nlsz
    SKIP
  ENDDO
ENDIF

ещё быстрее.
...
Рейтинг: 0 / 0
26.03.2010, 13:49
    #36544589
karly™
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
ШестипаловIF SEEK(nlsz)
DO WHILE id_ls=nlsz
SKIP
ENDDO
ENDIF

ещё быстрее.Согласен. Полезный прием, если между Do While и EndDo нужно выполнить несколько команд.

Здесь же все можно уложить в один Select
...
Рейтинг: 0 / 0
26.03.2010, 14:00
    #36544630
Как ускорить этот цикл? (выборка из архивных файлов по условию)
karly™Согласен. Полезный прием, если между Do While и EndDo нужно выполнить несколько команд.

Здесь же все можно уложить в один Select

А с этим согласен я :-)
...
Рейтинг: 0 / 0
26.03.2010, 14:25
    #36544726
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
Спасибо за ответы, буду экспериментировать и засекать условия и время выполнения.
...
Рейтинг: 0 / 0
26.03.2010, 15:23
    #36544911
quxix
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
А. С.Привет всем. Есть код, смысл его в том, что есть архивные файлы с оплатой, они находятся в папках для каждого месяца, а месяца разбиты по годам (но это не важно).
дерево такое:
2008
_01\oplata.dbf
_02\oplata.dbf
_03\oplata.dbf
_NN\oplata.dbf
2009
_01\oplata.dbf
_02\oplata.dbf
_03\oplata.dbf
_NN\oplata.dbf
Задача в курсор выбрать из всех таблиц записи по лицевому счету.
Можно ли еще ускорить этот процесс, может есть способы это делать быстрее, чем в приведенном коде?

Может сделать табличку в которой отобразить счета и соотв. им название табл оплат, в соответствии с которой тянуть данные с указанных таблиц. Т.е. не открывать те таблички в которых нет данных по указанному счету.
...
Рейтинг: 0 / 0
26.03.2010, 23:19
    #36545753
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
ШестипаловIF SEEK(nlsz)
DO WHILE id_ls=nlsz
SKIP
ENDDO
ENDIF

ещё быстрее.

Огромное СПАСИБО! Отрабатывает 40 архивных месяцев меньше 2-х секунд. Решение то на поверхности лежало. Век живи - век учись.
...
Рейтинг: 0 / 0
27.03.2010, 11:32
    #36546052
karly™
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
А. С. Век живи - век учисьНаучившегося использовать индексы в запросах так же ждут приятные открытия ;)
...
Рейтинг: 0 / 0
27.03.2010, 12:03
    #36546074
А. С.
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
Да дело в том что программирую на Фоксе достаточно давно, но никогда не думал что в селекте могут использоваться индексы.
...
Рейтинг: 0 / 0
30.03.2010, 09:42
    #36549723
leaf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
главное найти начало стопки ...
иначе для чого индекс то?
...
Рейтинг: 0 / 0
31.03.2010, 11:58
    #36552458
Zmej
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как ускорить этот цикл? (выборка из архивных файлов по условию)
ШестипаловИМХО,

IF SEEK(nlsz)
DO WHILE id_ls=nlsz
SKIP
ENDDO
ENDIF

ещё быстрее.
Теоретически:
Код: plaintext
1.
2.
3.
4.
5.
IF SEEK(nlsz)
  SCAN WHILE id_ls=nlsz

  ENDSCAN
ENDIF
должно быть еще быстрее
А вообще - чтобы покороче, то весь кусок:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
				SET ORDER TO tag id_ls
					SET KEY TO nlsz
					SCAN
						SCATTER TO eee
						SELECT cTemp
						APPEND BLANK
						GATHER FROM eee
					ENDSCAN
можно заменить на
Код: plaintext
INSERT INTO cTemp (имяПоля1, имяПоля2,....) SELECT имяПоля1, имяПоля2,.... FROM tmp WHERE tmp.id_ls = nlsz
правда придется перечислять имена полей...
Да, чуть не забыл, для проверки оптимизируемости SQL выражений (если тормозит SELECT) можно использовать функцию SYS(3054). Т.е. где-то так
Код: plaintext
1.
2.
SYS( 3054 , 1 )                   && включаем вывод сообщения об оптимизации на экран
INSERT INTO cTemp (имяПоля1, имяПоля2,....) SELECT имяПоля1, имяПоля2,.... FROM tmp WHERE tmp.id_ls = nlsz
SYS( 3054 , 1 )                   && отключаем
Как Вы понимаете эту функцию нужно использовать только на этапе отладки приложения.
...
Рейтинг: 0 / 0
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Как ускорить этот цикл? (выборка из архивных файлов по условию) / 21 сообщений из 21, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]