powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Увеличить скорость расчета остатков
6 сообщений из 6, страница 1 из 1
Увеличить скорость расчета остатков
    #32752061
Danil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В связи с тем, что объем таблиц для прихода и расхода увеличивается, расчет остатков стал длиться очень долго. Расчитываются остатки путем вычитания из прихода всего расхода. Не хотелось бы заниматься "резкой" таблиц по периодам, а м.б. поменять алгоритм или что нибудь еще...
Товары приходуются в упаковках, расходоваться же могут упаковками и штуками.
Пример выборки, которая и отрабатывает очень долго:
SELECT r.id,r.cnt,sum(IIF(e.log=0,e.cnt,0)) as e_cnt,sum(IIF(e.log=1,e.cnt,0)) as e_cnt_p,;
MAX(ALLTRIM(m.name)+IIF(ISNULL(p.name),'',' '+ALLTRIM(p.name))) as medname,;
MAX(r.retailprice) as retailprice,;
000000000000+MAX(IIF(n.countinpack=0,1,n.countinpack)) as cntinpack, r.barcode as barcode,MAX(r.apptyme) as app_tyme ,;
max(TTOD(d.date)) as date,'' as inv_no;
FROM receipts r,expenses e,documents d,medications m,nomenclatures n LEFT OUTER JOIN produsers p ON n.prod_id=p.id;
WHERE r.id=e.rcpt_id AND n.id=r.nom_id AND n.med_id=m.id AND d.id=r.doc_id AND d.closed AND d.store_id=goApp.nStoreHouse_ID AND d.closed;
GROUP BY r.id,r.cnt, r.barcode ;
UNION all;
select r.id,r.cnt,0 as e_cnt,0 as e_cnt_p,;
ALLTRIM(m.name)+IIF(ISNULL(p.name),'',' '+ALLTRIM(p.name)) as medname,r.retailprice,;
000000000000+IIF(n.countinpack=0,1,n.countinpack) as cntinpack, r.barcode as barcode,r.apptyme as app_tyme,;
TTOD(d.date) as date,'' as inv_no;
FROM receipts r,documents d,medications m,nomenclatures n LEFT OUTER JOIN produsers p ON n.prod_id=p.id ;
WHERE n.id=r.nom_id AND n.med_id=m.id AND d.id=r.doc_id AND d.closed AND d.store_id=goApp.nStoreHouse_ID AND d.closed;
AND NOT r.id in (select DISTINCT e.rcpt_id as id FROM expenses e );
INTO CURSOR _rest READWRITE
далее куски кода отрабатыват достаточно быстро. В них происходит:
REPLACE ALL e_cnt WITH cnt-e_cnt-CEILING(e_cnt_p/cntinpack),;
e_cnt_p WITH IIF(MOD(e_cnt_p,cntinpack)=0,0,cntinpack-MOD(e_cnt_p,cntinpack))

Flt_Expr=IIF(m.tlWithNull,'','WHERE e_cnt#0 OR e_cnt_p#0')
INSERT into rem_tg ;
SELECT id , medname as name, retailprice as price ,e_cnt as cnt,e_cnt_p as cnt_p,cntinpack,barcode,app_tyme,date,inv_no ;
FROM _rest &Flt_Expr &&WHERE e_cnt+e_cnt_p>0
USE IN _rest
...
Рейтинг: 0 / 0
Увеличить скорость расчета остатков
    #32752080
Dushes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
тихо сам с собою я веду беседу?

С уважением
duШes
....кто здесь?!!!!! ;)
...
Рейтинг: 0 / 0
Увеличить скорость расчета остатков
    #32752083
Danil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dushesтихо сам с собою я веду беседу?

С уважением
duШes
....кто здесь?!!!!! ;)
Зачем же сам с собой ведешь беседу? Это уже нехороший признак :-))))
Вопрос звучал как (ведержки):
1. Как оптимизировать запрос, который отрабатывает долго?
2. Иной более оптимальный (по скорости выполнения) алгоритм?
...
Рейтинг: 0 / 0
Увеличить скорость расчета остатков
    #32752240
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если уж ты спрашиваешь про запрос, то постарайся написать его в удобочитаемом виде. Это для тебя здесь все просто и понятно. Вот смотри, я просто переписал твой запрос в удобочитаемом виде:

Код: 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.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
SELECT ;
	r.id, ;
	r.cnt, ;
	SUM(IIF(e.log= 0 ,e.cnt, 0 )) as e_cnt, ;
	SUM(IIF(e.log= 1 ,e.cnt, 0 )) as e_cnt_p, ;
	MAX(PADR(ALLTRIM(m.name)+NVL(' '+ALLTRIM(p.name),''), 50 )) as medname, ;
	MAX(r.retailprice) as retailprice, ;
	MAX(IIF(n.countinpack= 0 , 000000000001 ,n.countinpack)) as cntinpack, ;
	r.barcode as barcode, ;
	MAX(r.apptyme) as app_tyme, ;
	MAX(TTOD(d.date)) as date, ;
	SPACE( 10 ) as inv_no ;
FROM receipts r ;
INNER JOIN expenses e ON r.id=e.rcpt_id ;
INNER JOIN documents d ON d.id=r.doc_id ;
INNER JOIN nomenclatures n ON n.id=r.nom_id ;
INNER JOIN medications m ON n.med_id=m.id ;
LEFT JOIN produsers p ON n.prod_id=p.id ;
WHERE d.store_id=goApp.nStoreHouse_ID ;
	AND d.closed=.T. ;
GROUP BY ;
	r.id, ;
	r.cnt, ;
	r.barcode ;
UNION ALL ;
SELECT ;
	r.id, ;
	r.cnt, ;
	 0  as e_cnt, ;
	 0  as e_cnt_p, ;
	PADR(ALLTRIM(m.name)+NVL(' '+ALLTRIM(p.name),''), 50 ) as medname, ;
	r.retailprice, ;
	IIF(n.countinpack= 0 , 000000000001 ,n.countinpack) as cntinpack, ;
	r.barcode as barcode, ;
	r.apptyme as app_tyme, ;
	TTOD(d.date) as date, ;
	'' as inv_no ;
FROM receipts r ; 
INNER JOIN documents d ON d.id=r.doc_id ;
INNER JOIN nomenclatures n ON n.id=r.nom_id ;
INNER JOIN medications m ON n.med_id=m.id ;
LEFT JOIN produsers p ON n.prod_id=p.id ;
WHERE d.store_id=goApp.nStoreHouse_ID ;
	AND d.closed=.T. ;
	AND r.id NOT IN (select e.rcpt_id FROM expenses e) ;
INTO CURSOR _rest READWRITE 

Кое-что, конечно, подправил. Но это косметические исправления. Несколько замечаний:

-) В твоем изначальном коде WHERE d.closed ... AND d.closed - зачем 2 раза писать одно и то же условие.
-) Крайне нежелатеьно для псевдонима таблицы использовать букву "m". В FoxPro под выражением типа "m.id" понимается прежде всего переменная памяти с именем "id" и только уже потом поле таблицы. Т.е. ты можешь нарваться на некорректную работу запроса
-) Вместо IIF(IsNull(),...,...) можно использовать NVL(...,...) Результат тот же, но выражение короче
-) Если ты используешь функции от строковых выражений (AllTrim()+...), то результат таких выражений надо явно добивать до фиксированного количества символов (PADR(AllTrim()+...,50)) чтобы поле в резуольтирующей выборке имело фиксированную размерность
-) Использовать пустую строку как выражение поля ('' as inv_no) крайне неразумно. Надо указать явную размерность (SPACE(10) as inv_no)
-) Я не совсем понял твой запрос, но мне непонятно, почему ты сделал UNION ALL вместо

FROM receipts r ;
LEFT JOIN expenses e ON r.id=e.rcpt_id ;

Ты же это имел в виду, когда писал NOT IN ?

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

-) Вообще-то, Select-SQL - это далеко не всегда самый быстрый способ пулучения выборки. Рассмотри вопрос прямого сканирования исходных таблиц и явного заполнения временной таблицы - результата выборки. Что-то вроде:

Код: plaintext
1.
2.
3.
4.
5.
CREATE CURSOR _rest (...)
SELECT documents 
SCAN FOR d.store_id=goApp.nStoreHouse_ID AND d.closed=.T.
...
INSERT INTO _rest (...) VALUES (...)
ENDSCAN
...
Рейтинг: 0 / 0
Увеличить скорость расчета остатков
    #32752371
Danil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ВладимирМ
Спасибо большое!
Ваши ответы и рекомендации всегда отличаются четкость изложения и глубоким и многосторонним знанием проблемы.
Данный запрос писал не я, а другой товарищ! Он так же сказал, что оптимизировал select до 3-х таблиц и не получил выигрыша в скорости.
Говорит, проблема в том, что объемы таблиц очень большие, допустим таблица
receipts = 30MB (приход)
expenses = 40 Mb (расход)
Я сейчас подумаю как scan спользовать или вот такой алгоритм:
1) С помощью select получить выборку по всему расходу сгруппированному по конкретным приходным позициям с сумированием соответ. полей e.rcpt_id
2) уст-ть связь receipts.id с expenses.rcpt_id
3)scan по receipts и expenses и вычитать и кидать в новую таблицу результат
...
Рейтинг: 0 / 0
Увеличить скорость расчета остатков
    #32752480
Фотография ВладимирМ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так, кое-что проясняется. Попробуй сделать так:

1) Делаешь выборку ТОЛЬКО по приходам
2) Делаешь выборку ТОЛЬКО по расходам
3) Объединяешь первые 2 выборки (по LEFT JOIN)

У тебя самые большие таблицы - это "приход" и "расход". В общем случае, объединение этих таблиц в одном запросе будет работать медленне, чем 2 отдельных запроса. Хотя, опять же, не факт. Это надо экспериметировать.

Тебе поможет функция SYS(3054) для определения уровня оптимизации запроса. Будет понятно, какие индексы надо добавить. Хотя, SYS(3054) тоже далека от совершенства. Опять же, факт полной оптимизации вовсе не говорит о том, что запрос будет выполняться быстрее. Вполне может быть, что полная оптимизиация замедлит выполнение запроса.
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / FoxPro, Visual FoxPro [игнор отключен] [закрыт для гостей] / Увеличить скорость расчета остатков
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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