На входе две таблицы значений. В одной - реализации, а другой - оплаты. Связаны только через значения реквизитов Организация+Контрагент+Договор+ТорговыйПредставитель. То есть по ссылкам не связаны.

Нужно получить третью таблицу так, чтобы видно было какие оплаты какие реализации погасили.
- Причём если оплата одного платёжного документа перекрывает остаток по долгу текущей реализации, то остаток по оплате переходит для оплаты следующей реализации.
- Причём на одну реализацию могут быть несколько оплат, но и может быть ситуация, когда одна оплата покрывает несколько реализаций.
- Причём вполне могут быть отмены проведения и/или перепроведения с другой датой как реализаций, так и оплат.
- Причём у реализаций есть реквизит СрокОплаты. Если последняя оплата по дате больше, чем СрокОплаты а долг по реализации ещё есть или текущая дата больше, чем СрокОплаты а долг по реализации опять есть, то реализация считается просроченной.

Таблица нужна, чтобы получить отчет по просроченным реализациям.

Сейчас работает так:
1. Выбираю текущую реализацию.
2. Выбираю все оплаты с совпадающими Организация+Контрагент+Договор+ТорговыйПредставитель
3. Начиная от первой по времени начинаю "компенсировать" долг по этой реализации.
4. Если текущая оплата ещё не погасила полностью долг по текущей реализации, то из входящей таблицы оплат эту оплату удаляю, чтобы она не попалась мне на следующей итерации.
5. Если текущая оплата полностью погасила долг по текущей оплате, то сумму оплаты во входящей таблице оплат изменяю на сумму остатка от текущей оплаты, чтобы на следующей итерации в проверке оплат участвовал только остаток от оплаты на предыдущем шаге итерации.
6. На следующей итерации таблица оплат меньше, ибо из неё удалены те оплаты, которые уже "отработали" и полностью вошли в оплату предыдущих реализаций.

На малом количестве документов всё прекрасно работает. Но сейчас входящие таблицы реализаций и оплат составляют по 150тыс строк. Отчет банально вылетает с ошибкой о превышении доступной оперативной памяти. Я понимаю, что на 32-битном серваке на одну сессию 1С выделяется 4МГб памяти.

Помогите оптимизировать алгоритм.
---
До цикла:

```1c
    ТабОплат.Индексы.Добавить("Организация,Контрагент,ДоговорКонтрагента,ТорговыйПредставитель");
```
---
Помогите оптимизировать алгоритм.
Попробуйте все это сделать в СКД, два набора данных, связи между ними, расчеты, отборы, и расшифровки
отчет можно сделать из двух частей
1.общая итоговая где в разрезе контрагентов показывает итоги Задолженность или Переплату
2.при клике на нужном контрагенте-договоре(что там еще) формируете детальный отчет с Реализациям и Оплатами
все просто летать будет
---
Я думал об этом. Не смог реализовать в запросе логику сравнения реализаций и оплат. Там как-то всё сложно получается.
---
Если вы ждете советы по алгоритму, то попробуйте выложить в открытый доступ (https://www.1c-cod.ru/) или прикрепить файл, без конкретики сложно посоветовать что-то дельное.

Ограничение по потреблению можно попробовать обойти следующим образом:
1. Подготовить две таблицы.
2. Выгрузить в файлы.
3. Сам алгоритм перенести на oscript.
4. Из 1с запустить скрипт (пункт 3), и получить результат его выполнения.
---
Вот цикл обработки

Код
   Для Каждого СтрокаПродажи Из ТабПродажи Цикл

      СтрокаЗадолженности = ПросроченныеЗадолженности.Добавить();
      ЗаполнитьЗначенияСвойств(СтрокаЗадолженности, СтрокаПродажи);

      СтрокаЗадолженности.ДокументПродажи = СтрокаПродажи.Регистратор;
      СтрокаЗадолженности.СуммаЗадолженности = СтрокаПродажи.Реализация;
      СтрокаЗадолженности.Просрочено = 0;

      ОтборОплат = Новый Структура("Организация,Контрагент,ДоговорКонтрагента,ТорговыйПредставитель");
      ЗаполнитьЗначенияСвойств(ОтборОплат, СтрокаПродажи);

      МассивУдаления = Новый Массив;
      СтрокиОплат = ТабОплат.НайтиСтроки(ОтборОплат);
      Если СтрокиОплат.Количество() = 0 Тогда
         Если ПериодЗапроса > СтрокаЗадолженности.ДатаОплаты Тогда
            СтрокаЗадолженности.Просрочено = СтрокаПродажи.Реализация;
         КонецЕсли;
         Продолжить;
      КонецЕсли;

      ВсегоПросрочено = 0;
      СуммаПродажи = СтрокаПродажи.Реализация;
      Для Каждого СтрОплата Из СтрокиОплат Цикл

         Если СуммаПродажи = 0 И СтрОплата.Оплата > 0 Тогда
            Прервать;
         КонецЕсли;

         СтрокаЗадолженности = ПросроченныеЗадолженности.Добавить();
         ЗаполнитьЗначенияСвойств(СтрокаЗадолженности, СтрОплата);
         СтрокаЗадолженности.ДокументПродажи = СтрокаПродажи.Регистратор;
         СтрокаЗадолженности.ДатаОплаты = СтрокаПродажи.ДатаОплаты;

         СписатьДолг = Мин(СуммаПродажи, СтрОплата.Оплата);

         СтрокаЗадолженности.СуммаЗадолженности = - СписатьДолг;
         СтрОплата.Оплата = СтрОплата.Оплата - СписатьДолг;
         ВсегоПросрочено = ВсегоПросрочено + СписатьДолг;

         СуммаПродажи = СуммаПродажи - СписатьДолг;

         Если СтрОплата.Оплата = 0 Тогда
            МассивУдаления.Добавить(СтрОплата);
         КонецЕсли;
      КонецЦикла;

      Для Каждого СтрУдаления Из МассивУдаления Цикл
         ТабОплат.Удалить(СтрУдаления);
      КонецЦикла;

      ОстатокДолга = СтрокаПродажи.Реализация - ВсегоПросрочено;
      Если ПериодЗапроса > СтрокаЗадолженности.ДатаОплаты И ОстатокДолга > 0 Тогда
         СтрокаЗадолженности = ПросроченныеЗадолженности.Добавить();
         ЗаполнитьЗначенияСвойств(СтрокаЗадолженности, СтрокаПродажи, , "Реализация");
         СтрокаЗадолженности.ДокументПродажи = СтрокаПродажи.Регистратор;
         СтрокаЗадолженности.Просрочено = ОстатокДолга;
      КонецЕсли;

   КонецЦикла;
Показать полностью
---
ТабОплат.НайтиСтроки(ОтборОплат);
До цикла добавить индекс по полям отбора, если его там еще нет.

Ну и сделать сначала замер производительности, чтобы знать что именно потребляет время, и что надо оптимизировать.

99% в приведенном коде - это НайтиСтроки.
---
Спасибо. Это дельный совет, это я лоханулся. Посмотрю, как можно сделать.
Замеры делались. И - да - именно на этом операторе вываливается больше всего времени.
---
До цикла:

```1c
    ТабОплат.Индексы.Добавить("Организация,Контрагент,ДоговорКонтрагента,ТорговыйПредставитель");
```
---
СПС
---
Но возникает вопрос: после каждого удаления строк из ТабОплат нужно заново добавлять индексы?
---
Нет.
Если в таблицу индексы добавлены, то они пересчитываются при добавлении/удалении строк.
Поэтому иногда бывает оптимальнее удалить индексы перед массовым добавлением/удалением строк, а потом заново добавить.
Т.к. наличие индексов немного увеличивает время на действия, связанные с изменением таблицы.
Как лучше будет - смотреть в замере.
---
У меня только удаление строк. Но зато в цикле.
СПС.
---
Можно не удалять строки. Добавить к таблицу колонку булевую, Обработан.
И вместо удаления строки, ставить ей признак Истина.
Соответственно, эту колонку надо добавить в отбор и индекс.
---
Тоже дельная мысль.
СПС
---
После добавления индекса в таблицу, все равно долго работает?
---
Помогло. Значительно быстрее отрабатывает.
Но теперь вывод в отчет медленно. Всё-таки итоговая таблица практически равна сложению двух входных.
Вот здесь:

Код
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
Показать полностью

)))
 Но это уже другая проблема...
---
Но теперь вывод в отчет медленно. Всё-таки итоговая таблица практически равна сложению двух входных.

А что потом с таким отчетом делать? Как его анализировать, если в нем 300к строк?
---
Если честно, то не знаю
---
Этот алгоритм называется ФИФО и все уже давно придумано. Самый оптимальный способ связи - фиксировать эту связь в каком-нибудь регистре ВзаиморасчотовПоДокументамОплаты.
---
К сожалению это не выход. При перепроведении или удалении одного любого документа нужно будет пересчитывать весь регистр.
---
Любой другой алгоритм обработки "на ходу" рано или поздно упрется в объемы. А для сохранения последовательности придумали - внезапно - последовательности)) Вы изобретаете велосипед, в типовых все реализовано.
---
При перепроведении или удалении одного любого документа нужно будет пересчитывать весь регистрДопустим, не весь, а только с точки изменения. И только при изменении. А ваш алгоритм подразумевает пересчет при каждом формировании.
---
Так была сформулирована задача. Речь о фиксации данных в регистре не стоит. К сожалению.
---
Я может ща глупость скажу, но чтобы избавится от ФИФО можно ж ведь подобие РАУ сделать, только применительно к оплатам, не?
---
Где найти информацию об этом алгоритме?
---
В той же УТ11 применительно к складскому учету, но это чисто реализация в коде. Теорию - не знаю, вероятно на ИТС по ключевым словам Расширенная Аналитика Учета.
---
Хор. Поищу информацию на эту тему.
---
Если проблема с нехваткой памяти, пробуйте читать обе исходные таблицы последовательно с диска, и записывать результат также последовательно. Время на обработку, конечно, при этом увеличится
---
К сожалению, это тоже не выход. У меня и так отчёт формируется 1 час. Увеличить скорость обработки - одна из задач.
---
И все-таки предложение организационное: закрытые (полностью оплаченные) на определенном временном интервале реализации в следующих расчетах не брать в расчет. Оплаты на конец того же временного промежутка также либо полностью расходованы, либо имеют остаток и также берутся в очередной расчет только имеющие остаток, а не все. Думаю, что если не разбивать на временные периоды (как, собственно, в учете всегда и делается), рано или поздно проблема с объемами информации возникнет.
---
Наверно так и будет. Но мы пока решаем проблемы по мере их поступления )))
---
может это поможет