Имя: Пароль:
1C
 
Накопительный итог 1С
0 ОператорПК
 
07.02.11
16:16
Здравствуйте.

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


РТиУ №01    100
РТиУ №02    500
РТиУ №03    80
РТиУ №04    200


Нужна таблица:

РТиУ №01    100    880
РТиУ №02    500    780
РТиУ №03    80    280
РТиУ №04    200    200

Какой самый быстрый способ ее получить?

Сейчас используется конструкция:

ВЫБРАТЬ
               ВТ2.Регистратор,
               СУММА(ВТ3.СуммаУпр) КАК СуммаУпр
ПОМЕСТИТЬ ВТ42
ИЗ
               ВТ2 КАК ВТ2
                              ЛЕВОЕ СОЕДИНЕНИЕ ВТ2 КАК ВТ3
                              ПО ВТ2.МоментВремени <= ВТ3.МоментВремени
СГРУППИРОВАТЬ ПО
               ВТ2.Регистратор

Но для большого количества документов работает дико медленно. Собственно вопрос каким  запросом можно получить тот – же результат за меньшее время?
1 mikecool
 
07.02.11
16:19
выбрать в ТЗ, пробежаться посчитать?
2 Axel2009
 
07.02.11
16:19
ТЗ обработать?
3 Asmody
 
07.02.11
16:19
самый быстрый - правильно использовать регистры
4 ОператорПК
 
07.02.11
16:20
Запрос состоит из множества пакетов (этот один из промежуточных).
5 zak555
 
07.02.11
16:20
ты бы хотть так написал бы :

РТиУ №01    200    200
РТиУ №02     80    280
РТиУ №03    500    780
РТиУ №04    100    880
6 ОператорПК
 
07.02.11
16:21
(5) мне нужно так как написано в (0). хотя это не принцыпиально.
7 Axel2009
 
07.02.11
16:24
индексы по моментвремени+суммаупр попробовать
8 ОператорПК
 
07.02.11
16:26
(7) по моменту времени нет индексации.
9 shuhard
 
07.02.11
16:29
(8) Рг накопления прикрутить уже поздно ?
10 ОператорПК
 
07.02.11
16:30
(9) да
11 shuhard
 
07.02.11
16:32
(10) та же 25 Гбайт мясная база ?
12 Axel2009
 
07.02.11
16:32
условия сделать на дату + ссылку и по ним индексы
13 ОператорПК
 
07.02.11
16:33
(11) нет 150 Гб (наш филиальчеГ) :))
14 acsent
 
07.02.11
16:36
(9) Чем регистр накопления поможет?
15 ОператорПК
 
07.02.11
16:40
(12) попробывал, не канает...
16 Axel2009
 
07.02.11
16:41
(15) чем не канает?
17 zak555
 
07.02.11
16:43
а если сделать так для печатной формы
цикл Группировка(1)
 КонОстВышестоящей = ЗАпрос.Сальдо;
Цикл ГРуппировка(2)
  КонОстТекДок = Запрос.Сальдо - КонОстВышестоящей
18 ОператорПК
 
07.02.11
16:43
(16) быстрее не стало работать.
19 ОператорПК
 
07.02.11
16:44
(17) результат запроса в (0) не конечный он еще многократно обрабатывается.
20 73
 
07.02.11
16:45
21 zak555
 
07.02.11
16:45
(19) что ещё ?
22 fisher
 
07.02.11
16:45
23 ОператорПК
 
07.02.11
16:46
(20) то же самое...
24 73
 
07.02.11
16:48
(23) Что то же? Ты хоть почитай. Условие как у тебя. Решение там - пост 10.
25 shuhard
 
07.02.11
16:48
(22) предлагаешь курсор сделать ?
26 ОператорПК
 
07.02.11
16:50
(24) тот же коннект ПериодыИзменения.Период >= Регистр.Период
что нового я там должен увидить?
27 ОператорПК
 
07.02.11
16:51
(25) чево за курсор как по одноэсовски будет?
28 Axel2009
 
07.02.11
16:51
(18) и какой же индекс был использован?
29 73
 
07.02.11
16:52
(26) А что ты хочешь увидЕть?
Если решение - то оно там.
Что ещё?
30 fisher
 
07.02.11
16:53
(26) Да, в самом деле... Извини. Мож в комментах что полезное.
31 ОператорПК
 
07.02.11
16:53
(28)
ИНДЕКСИРОВАТЬ ПО
   Регистратор,
   СуммаУпр
-только не понятно как этот индекс может ускорить соединение по МоментВремени.
32 fisher
 
07.02.11
16:55
(30) + Мда... Ничего применимого к 1С в комментах не нашел. Все более быстрые способы к 1С не применимы.
33 ОператорПК
 
07.02.11
16:58
(29) обычно одну и туже задачу можно решить разными способами вот я и спрашиваю про другой способ т.к. этот способ давольно медленно работает в моем случае.
34 shuhard
 
07.02.11
16:59
(27)[как по одноэсовски будет]
ни как
отдаленный аналог курсора - временная таблица, её ты уже использовал
35 Axel2009
 
07.02.11
16:59
(31) если не помог, значит ничего больше не поможет..
если только не извращаться и уменьшать количество обрабатываемых строк.. в цикле там обрабатывать..
36 shuhard
 
07.02.11
17:00
(33) дык вариант с накоплением итога по регистратору в Рг накопления ты отверг
37 ОператорПК
 
07.02.11
17:03
(36) как мне его накопить? допустим есть пары Договор+Контрагент один пользователь захочет посмотреть в разрезе одного договора другой в разрезе всех.... у меня нет четкого соответствия Регистратор-Накопительный итог.
38 ОператорПК
 
07.02.11
17:03
Договор+Контрагент=Договор+регистратор сори...
39 fisher
 
07.02.11
17:04
(33) Судя по всему, на голом SELECTе быстрее никак. В T-SQL более быстрые варианты реализуют курсорами и DML.
40 Axel2009
 
07.02.11
17:08
(38) не зная полной задачи , трудно посоветовать. может удастся както обойти этот пересчет. и сколько документов попадает под пересчет обычно?
41 ОператорПК
 
07.02.11
17:10
40 тыс. документов "на входе".
42 Axel2009
 
07.02.11
17:12
и сколько отрабатывает по времени? и если "на входе" будет 1000 доков, скока будет отрабатывать?
43 Axel2009
 
07.02.11
17:13
800млн строк обработать - не шухры мухры =)
44 ОператорПК
 
07.02.11
17:13
(42) минут 10-20 не замерял точно.
45 Axel2009
 
07.02.11
18:01
в таблице 890 строк

   Запрос = Новый Запрос;
   Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
   Запрос.Текст =
   "ВЫБРАТЬ ПЕРВЫЕ 20000
   |    Продажи.Регистратор КАК Регистратор,
   |    СУММА(Продажи.Стоимость) КАК Стоимость
   |ПОМЕСТИТЬ ТестОбороты
   |ИЗ
   |    РегистрНакопления.Продажи КАК Продажи
   |
   |СГРУППИРОВАТЬ ПО
   |    Продажи.Регистратор
   |;
   |
   |////////////////////////////////////////////////////////////////////////////////
   |ВЫБРАТЬ
   |    ТестОбороты_1.Регистратор,
   |    СУММА(ТестОбороты_2.Стоимость) КАК Стоимость
   |ИЗ
   |    ТестОбороты КАК ТестОбороты_1
   |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТестОбороты КАК ТестОбороты_2
   |        ПО ТестОбороты_1.Регистратор >= ТестОбороты_2.Регистратор
   |
   |СГРУППИРОВАТЬ ПО
   |    ТестОбороты_1.Регистратор
   |УПОРЯДОЧИТЬ ПО Стоимость";
   ТЗ = Запрос.Выполнить().Выгрузить();
запрос отработал 1,4с


   Запрос = Новый Запрос;
   Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
   Запрос.Текст =
   "ВЫБРАТЬ ПЕРВЫЕ 20000
   |    Продажи.Регистратор КАК Регистратор,
   |    СУММА(Продажи.Стоимость) КАК Стоимость
   |ПОМЕСТИТЬ НД1
   |ИЗ
   |    РегистрНакопления.Продажи КАК Продажи
   |
   |СГРУППИРОВАТЬ ПО
   |    Продажи.Регистратор;
   |ВЫБРАТЬ ПЕРВЫЕ 0 Регистратор, Стоимость ПОМЕСТИТЬ КД2 ИЗ НД1";
   Запрос.Выполнить();
   ИмяИтоговойТаблицы = "";
   Пока Истина Цикл
       ОбработкаПрерыванияПользователя();
       Запрос.Текст =
       "ВЫБРАТЬ ПЕРВЫЕ 200
       | Регистратор, Стоимость
       |ПОМЕСТИТЬ ПД
       |ИЗ НД1
       |УПОРЯДОЧИТЬ ПО Регистратор;
       |
       |ВЫБРАТЬ ПД1.Регистратор, СУММА(ПД2.Стоимость)+ЕСТЬNULL(ДопСумма.Стоимость, 0) КАК Стоимость
       |ПОМЕСТИТЬ КД1
       |ИЗ ПД КАК ПД1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПД КАК ПД2 ПО ПД1.Регистратор >= ПД2.Регистратор
       |ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ МАКСИМУМ(Стоимость) КАК Стоимость ИЗ КД2) КАК ДопСумма ПО ИСТИНА
       |СГРУППИРОВАТЬ ПО ПД1.Регистратор, ДопСумма.Стоимость
       |ОБЪЕДИНИТЬ ВСЕ
       |ВЫБРАТЬ Регистратор, Стоимость ИЗ КД2;
       |
       |ВЫБРАТЬ НД1.Регистратор КАК Регистратор, НД1.Стоимость КАК Стоимость
       |ПОМЕСТИТЬ НД2
       |ИЗ НД1 ЛЕВОЕ СОЕДИНЕНИЕ КД1 ПО НД1.Регистратор = КД1.Регистратор
       |ГДЕ КД1.Регистратор ЕСТЬ NULL;
       |УНИЧТОЖИТЬ НД1;
       |УНИЧТОЖИТЬ КД2;
       |УНИЧТОЖИТЬ ПД;
       |ВЫБРАТЬ ПЕРВЫЕ 1 Регистратор ИЗ НД2";
       ВыборкаПроверка = Запрос.Выполнить().Выбрать();
       Если Не ВыборкаПроверка.Следующий() Тогда
           ИмяИтоговойТаблицы = "КД1";
           Прервать;
       КонецЕсли;
       
       Запрос.Текст =
       "ВЫБРАТЬ ПЕРВЫЕ 200
       | Регистратор, Стоимость
       |ПОМЕСТИТЬ ПД
       |ИЗ НД2
       |УПОРЯДОЧИТЬ ПО Регистратор;
       |
       |ВЫБРАТЬ ПД1.Регистратор, СУММА(ПД2.Стоимость)+ДопСумма.Стоимость КАК Стоимость
       |ПОМЕСТИТЬ КД2
       |ИЗ ПД КАК ПД1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПД КАК ПД2 ПО ПД1.Регистратор >= ПД2.Регистратор
       |ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ МАКСИМУМ(Стоимость) КАК Стоимость ИЗ КД1) КАК ДопСумма ПО ИСТИНА
       |СГРУППИРОВАТЬ ПО ПД1.Регистратор, ДопСумма.Стоимость
       |ОБЪЕДИНИТЬ ВСЕ
       |ВЫБРАТЬ Регистратор, Стоимость ИЗ КД1;
       |
       |ВЫБРАТЬ НД2.Регистратор КАК Регистратор, НД2.Стоимость КАК Стоимость
       |ПОМЕСТИТЬ НД1
       |ИЗ НД2 ЛЕВОЕ СОЕДИНЕНИЕ КД2 ПО НД2.Регистратор = КД2.Регистратор
       |ГДЕ КД2.Регистратор ЕСТЬ NULL;
       |УНИЧТОЖИТЬ НД2;
       |УНИЧТОЖИТЬ КД1;
       |УНИЧТОЖИТЬ ПД;
       |ВЫБРАТЬ ПЕРВЫЕ 1 Регистратор ИЗ НД1";
       ВыборкаПроверка = Запрос.Выполнить().Выбрать();
       Если Не ВыборкаПроверка.Следующий() Тогда
           ИмяИтоговойТаблицы = "КД2";
           Прервать;
       КонецЕсли;
   КонецЦикла;
   Запрос.Текст =
   "ВЫБРАТЬ Регистратор, Стоимость ИЗ " + ИмяИтоговойТаблицы + " УПОРЯДОЧИТЬ ПО Регистратор";
   ТЗ = Запрос.Выполнить().Выгрузить();
отработал за 0.6сек

на количестве данных 40000 будет еще существеннее.

за минутку может и отработать.. быстрее хз как =)
46 IKSparrow
 
07.02.11
19:09
А разве через таблицу оборотов не получается искомое?
47 Axel2009
 
07.02.11
19:50
(46) вопрос не в искомом, а в скорости получения искомого.
48 fisher
 
08.02.11
10:54
(45) Вопрос, как поведет себя такая методика на многомиллионных таблицах в сравнении с обычным методом. Сравни, плиз, с шагом в лимонов 5 строк несколько замеров. У тебя ведь всё готово уже. Очень интересно тенденцию отследить.
Насколько замедлит работу многократное переливание туда-сюда огромной исходной таблицы (с выкусыванием обработанных порций). Ведь замедление этой операции замедляет работу всего алгоритма в геометрической прогрессии. Хочется понять, насколько метод применим на больших таблицах.
Кстати, ЛЕВОЕ СОЕДИНЕНИЕ ПО ИСТИНА можно заменить на стандартную запись декартова произведения в SQL - просто указав вторую таблицу через запятую без всяких соединений.
А Не ВыборкаПроверка.Следующий() на Запрос.Выполнить().Пустой()
49 Axel2009
 
08.02.11
10:59
(48) если будет 1млн строк, то присоединение из (0) даст обработку в 500 трл строк. сервер сдохнет..
а на счет "Пустой" тоже можно =)
50 fisher
 
08.02.11
11:01
(49) Вот не факт, что сдохнет. Тут практика важнее домыслов.
51 Axel2009
 
08.02.11
11:01
(49) ошибся, в 500блн строк
52 Axel2009
 
08.02.11
11:01
(50) у сервера стока оперативки нетю..
53 Axel2009
 
08.02.11
11:02
(51) не, трл =) чета засчитался. ща проверю на более больших данных
54 Axel2009
 
08.02.11
11:04
(50) ЗЫ на млн строк даж пробовать не буду =) сами пробуйте если хотите.
55 fisher
 
08.02.11
11:10
Ну, можно на меньших объемах. Главное хоть какой-то тренд наметить.
56 Axel2009
 
08.02.11
11:19
скульсервак (база на скуле, новые тесты). до этого была файловая база
проверка на 1000 строк
одним запросом: 0.55сек
обработкой по 200 строк: 0.77сек
обработкой по 500 строк: 1.3сек

проверка на 16 000 строк
одним запросом: 82сек
обработкой по 200 строк: 17сек
обработкой по 500 строк: 12.7сек
обработкой по 1000 строк: 13.1сек
57 fisher
 
08.02.11
11:29
Можно было бы полный аналог курсоров забабахать на порционных выборках (как 1С и делает в своих системных механизмах). Без переливания туда-сюда больших объемов.
Просто выбирать порции из последовательных диапазонов исходной таблицы по нужному ключу, обрабатывать и результаты накапливать. Извечная проблема с накоплением. Т.к. добавить в 1С строки во временную таблицу можно только её полным пересозданием... Сколько нужных вещей в эту фигню упирается...
58 fisher
 
08.02.11
11:30
(56) Спасибо. В общем, в независимости от оптимальности второго метода, первый однозначно идёт в топку на больших объемах...
59 Axel2009
 
08.02.11
11:31
(57) да много чего можно было бы.. только запросы в 1с только те что T-SQL. а курсоры - это дело каждой СУБДшки.. поэтому и не делают
60 fisher
 
08.02.11
11:33
(57) + Но всё равно будет быстрее твоего варианта, хотя и сложнее...
61 Axel2009
 
08.02.11
11:34
(60) а я и не спорю. =) в части накопительных сумм ток у Оракла знаю есть такая приблуда..
62 Axel2009
 
08.02.11
11:34
(61)+ ну и следующий скуль обещают наваять.. в 10ке.. хотя бета уже есть, можно глянуть. но на 1с это не отразится =)
63 fisher
 
08.02.11
11:36
(59) T-SQL это как раз курсоры :) Это название диалекта MSSQL.
Речь не о курсорах, их понятно почему нет. Речь о возможности INSERTов во временные таблицы. Это кучу бы возможностей дало.
64 Axel2009
 
08.02.11
11:39
(63) T-SQL - транзактСКЛ, стандарт собственно говоря,которая каждая СУБДшка должна поддерживать =)