В таблице значений заданы регистры правил.
Я ищу в ней по структуре методом ТЗ.НайтиСтроки(СтруктураПоиска).
Если не нахожу по детальному условию, убираю поля, ищу дальше.
Функция работы с регистром правил рекурсивная.
Поэтому я копирую структуру поиска и передаю ее в рекурсивный вызов.
Копирование работает медленно.
Как я не изощрялся - и через заполнение свойств и через хранилище. В итоге самый быстрый способ - это копирование перебором для Каждого из СтруктураПоиска Цикл СтруктураКОпия.Вставить(Кз.Ключ, Кз.Значение).

При работе получается около 3 млн проходов по этому циклу. На 3 млн прохода тратиться 40 секунд. Это много.

Можно как-то ускорить копирование структур?

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

Копия = ЗначениеИзСтрокиВнутр(Оригинал.ЗначениеВСтрокуВнутр()) пробовали?

Если задача переборная (подборная) нужно посмотреть на код Грэя. Он позволяет переходить от одного векторного решения к другому, заменяя один элемент. То есть предлагается не копировать структуру, а менять ее по одному элементу, восстанавливая на выходе из рекурсии.

Ну а вообще действительно есть смысл передать ТЗ во временную таблицу запроса, посчитать для каждой записи временной таблицы число совпадений с элементами критерия отбора и выбрать запись с максимальной суммой числа совпадающих элементов критерия, а затем определить по этой записи самый мощный отбор.
---
самый медленный способ, да пробовал.

Насчет анализа кода думал-думал, не придумал. Можно конечно удалять те свойства, что добавлены, но там слишком хитроумная логика, сложно.
хотя, возможно и придется заняться.

Вот функция:

```1c
    Функция ОпределитьКоэффициентИнтеграцииМагазина(СтруктураКоэффициентов, СтруктураПоискаИсх, ЗначениеПоУмолчанию = 0, Найден = ложь) Экспорт
    //СтруктураПоискаИсх - не разрушается.
    //Определяем искомый коэффициент...
    //В структуре поиска - поля поиска, ищет согласно приоритетов...

    ТаблицаКоэффициентов = СтруктураКоэффициентов.ТаблицаКоэффициентов;

    СтруктураПоиска = САП.СкопироватьСтруктуру(СтруктураПоискаИсх);

    //Запоминаем отдельно период
    Если СтруктураПоиска.Свойство("Период") Тогда
    Период = СтруктураПоиска.Период;
    СтруктураПоиска.Удалить("Период");
    Иначе
    Период = Неопределено;
    КонецЕсли;

    Если СтруктураПоиска.Свойство("ИгнорироватьОшибки") Тогда
    ИгнорироватьОшибки = СтруктураПоиска.ИгнорироватьОшибки;
    СтруктураПоиска.Удалить("ИгнорироватьОшибки");
    Иначе
    ИгнорироватьОшибки = ложь;
    КонецЕсли;

    Строки = ТаблицаКоэффициентов.НайтиСтроки(СтруктураПоиска);

    //Удаляем то, что не подходит под период
    Если Период <> Неопределено Тогда
    Всего = Строки.Количество();
    Для Инд = 1 По Всего Цикл
    Поз = Всего - Инд;
    Строка = Строки[Поз];
    Если НЕ (Период >= Строка.ДатаС И Период <= Строка.ДатаПо) Тогда
    Строки.Удалить(Поз);
    КонецЕсли;
    КонецЦикла;
    КонецЕсли;

    Если Строки.Количество() = 0 Тогда
    //Если не найден коэффициент по группе, ищем коэффициент без группы...
    СтруктураПоиска = САП.СкопироватьСтруктуру(СтруктураПоискаИсх);

    //Ищем по пустой группе, т.е. для всех групп...
    Если СтруктураПоиска.Свойство("Группа") И ЗначениеЗаполнено(СтруктураПоиска.Группа) Тогда
    СтруктураПоиска.Вставить("Группа", Справочники.спКатегорииПлановПродаж.ПустаяСсылка());
    СтруктураПоиска.Вставить("ИгнорироватьОшибки", истина);

    //Если без группы будут возникать ошибки, возвращаем значение по умолчанию.
    Найден = ложь;
    Результат = ОпределитьКоэффициентИнтеграцииМагазина(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден);
    Если Найден Тогда
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;

    //Подымаемся по иерархии элемента

    СтруктураПоиска = САП.СкопироватьСтруктуру(СтруктураПоискаИсх);

    //Используем кэш
    Если СтруктураПоиска.Свойство("Аналитика1") Тогда
    Элемент = СтруктураПоиска.Аналитика1;
    ТекРодитель = СтруктураКоэффициентов.КэшРодителей[Элемент];
    Если ТекРодитель = Неопределено Тогда
    Попытка
    ТекРодитель = СтруктураПоиска.Аналитика1.Родитель;
    Исключение
    ТекРодитель = NULL;
    КонецПопытки;
    СтруктураКоэффициентов.КэшРодителей.Вставить(Элемент, ТекРодитель);
    КонецЕсли;

    Если ЗначениеЗаполнено(ТекРодитель) Тогда
    СтруктураПоиска.Вставить("Аналитика1", ТекРодитель);
    СтруктураПоиска.Вставить("ИгнорироватьОшибки", истина);
    Найден = ложь;
    Результат = ОпределитьКоэффициентИнтеграцииМагазина(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден);
    Если Найден Тогда
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;
    КонецЕсли;

    //Ищем по пустой аналитике, т.е. для всех элементов...
    СтруктураПоиска = САП.СкопироватьСтруктуру(СтруктураПоискаИсх);
    Если СтруктураПоиска.Свойство("Аналитика1") И ЗначениеЗаполнено(СтруктураПоиска.Аналитика1) Тогда
    СтруктураПоиска.Вставить("Аналитика1", Неопределено);
    СтруктураПоиска.Вставить("ИгнорироватьОшибки", истина);
    Найден = ложь;
    Результат = ОпределитьКоэффициентИнтеграцииМагазина(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден);
    Если Найден Тогда
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;

    Найден = ложь;
    Возврат ЗначениеПоУмолчанию;
    КОнецЕсли;

    ТЗ = САП.КоллекцияВТаблицу(Строки, , ТаблицаКоэффициентов);

    //Соритруем по магазинам...
    ТЗ.Сортировать("ПриоритетПоМагазинам Возр");

    Если ТЗ.Количество() > 1 И ТЗ[1].ПриоритетПоМагазинам = ТЗ[0].ПриоритетПоМагазинам Тогда
    Если ИгнорироватьОшибки Тогда
    Возврат ЗначениеПоУмолчанию; //Возвращаем, что значение не найдено.
    Иначе
    Р = ";
    Для Каждого КЗ ИЗ СтруктураПоиска Цикл
    Р = Р + КЗ.Ключ + " = " + КЗ.Значение + Символы.ПС;
    КонецЦикла;
    САП.ПечатьТЗ(ТЗ);
    ВызватьИсключение "При расчете коэффициента по структуре поиска: " + Р + " выявлена неоднозначность назначения, нужно исправить назначенные коэффициенты!" ;
    КонецЕсли;
    КонецЕсли;

    Найден = истина;
    Возврат ТЗ[0].Значение;
    КонецФункции

    Функция СкопироватьСтруктуру(Источник) Экспорт

    Приемник = Новый Структура();
    Для Каждого КЗ Из Источник Цикл
    Приемник.Вставить(КЗ.Ключ, КЗ.Значение);
    КонецЦИкла;
    Возврат Приемник;

    КонецФункции
```
---
Странно, но текст функции (на первый взгляд) говорит о том, что никакие поля в отбор не добавляются и не удаляются. Отбор производится по двум полям "Группа" и "Аналитика1". Эти поля варьируются. Конкретные значения принадлежат произведению множеств: {ЗаданнаяГруппа, Пусто} и {ЗаданнаяАналитика, ЗаданнаяАналитика.Родитель, ЗаданнаяАналитика.Родитель.Родитель, ..., Пусто}.

Все это можно сделать без всякой рекурсии двумя вложенными циклами. Во внешнем перебирать аналитику (от листа к корню), во внутреннем группу, а когда отбор даст не пустой результат, вернуть его, проверив приоритеты.

ТЗ нужно проиндексировать по полям поиска.
---
это слишком частное решение.
У меня получилось таки победить, в большей степени благодаря (9)
Но всем большое спасибо.
Завтра выложу код, каким он получился.
---
Профессор Эльдорадович признал Ваш код гнилым. Следует учиться программировать у коллег, 9-10-11. Единственное, что интересно - во сколько раз ускорилось исполнение программы - по сравнению с первоначальными 40сек.
---
век живи - век учись. ;-)

Вот как переписал, если кому интересно, работает как часы. ;-)

```1c
    Функция ОпределитьКоэффициентИнтеграцииМагазина(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию = 0, Найден = ложь) Экспорт
    Перем Период;

    //Запоминаем отдельно период
    Если СтруктураПоиска.Свойство("Период") Тогда
    Период = СтруктураПоиска.Период;
    СтруктураПоиска.Удалить("Период");
    Иначе
    Период = Неопределено;
    КонецЕсли;

    Найден = ложь;

    Возврат ОпределитьКоэффициентИнтеграцииМагазинаСлуж(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден, ложь, Период);
    КонецФункции

    Функция ОпределитьКоэффициентИнтеграцииМагазинаСлуж(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию = 0, Найден = ложь, ИгнорироватьОшибки = ложь, Период = Неопределено) Экспорт

    ТаблицаКоэффициентов = СтруктураКоэффициентов.ТаблицаКоэффициентов;

    Строки = ТаблицаКоэффициентов.НайтиСтроки(СтруктураПоиска);

    //Удаляем то, что не подходит под период
    Если Период <> Неопределено Тогда
    Всего = Строки.Количество();
    Для Инд = 1 По Всего Цикл
    Поз = Всего - Инд;
    Строка = Строки[Поз];
    Если НЕ (Период >= Строка.ДатаС И Период <= Строка.ДатаПо) Тогда
    Строки.Удалить(Поз);
    КонецЕсли;
    КонецЦикла;
    КонецЕсли;

    Если Строки.Количество() = 0 Тогда
    //Если не найден коэффициент по группе, ищем коэффициент без группы...

    //Ищем по пустой группе, т.е. для всех групп...
    Если СтруктураПоиска.Свойство("Группа") И ЗначениеЗаполнено(СтруктураПоиска.Группа) Тогда

    //Если без группы будут возникать ошибки, возвращаем значение по умолчанию.
    Найден = ложь;
    ПредЗначение = СтруктураПоиска.Группа;
    СтруктураПоиска.Вставить("Группа", Справочники.спКатегорииПлановПродаж.ПустаяСсылка());
    Результат = ОпределитьКоэффициентИнтеграцииМагазинаСлуж(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден, истина, Период);
    СтруктураПоиска.Вставить("Группа", ПредЗначение);
    Если Найден Тогда
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;

    //Подымаемся по иерархии элемента

    //Используем кэш
    Если СтруктураПоиска.Свойство("Аналитика1") Тогда
    Элемент = СтруктураПоиска.Аналитика1;

    ИскСтрока = СтруктураКоэффициентов.КэшРодителей.Найти(Элемент, "Ключ");
    Если ИскСтрока = Неопределено Тогда
    Попытка
    ТекРодитель = СтруктураПоиска.Аналитика1.Родитель;
    Исключение
    ТекРодитель = Неопределено;
    КонецПопытки;

    Нстр = СтруктураКоэффициентов.КэшРодителей.Добавить();
    НСтр.Ключ = Элемент;
    НСтр.Значение = ТекРодитель;
    Иначе
    ТекРодитель = ИскСтрока.Значение;
    КонецЕсли;

    Если ЗначениеЗаполнено(ТекРодитель) Тогда

    Найден = ложь;
    ПредЗначение = СтруктураПоиска.Аналитика1;
    СтруктураПоиска.Вставить("Аналитика1", ТекРодитель);
    Результат = ОпределитьКоэффициентИнтеграцииМагазинаСлуж(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден, Истина, Период);
    СтруктураПоиска.Вставить("Аналитика1", ПредЗначение);

    Если Найден Тогда
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;
    КонецЕсли;

    //Ищем по пустой аналитике, т.е. для всех элементов...
    Если СтруктураПоиска.Свойство("Аналитика1") И ЗначениеЗаполнено(СтруктураПоиска.Аналитика1) Тогда
    Найден = ложь;
    ПредЗначение = СтруктураПоиска.Аналитика1;
    СтруктураПоиска.Вставить("Аналитика1", Неопределено);
    Результат = ОпределитьКоэффициентИнтеграцииМагазинаСлуж(СтруктураКоэффициентов, СтруктураПоиска, ЗначениеПоУмолчанию, Найден, Истина, Период);
    СтруктураПоиска.Вставить("Аналитика1", ПредЗначение);
    Если Найден Тогда
    Возврат Результат;
    КонецЕсли;
    КонецЕсли;

    Найден = ложь;
    Возврат ЗначениеПоУмолчанию;
    КОнецЕсли;

    ТЗ = САП.КоллекцияВТаблицу(Строки, , ТаблицаКоэффициентов);
    //Соритруем по магазинам...
    ТЗ.Сортировать("ПриоритетПоМагазинам Возр");

    Если ТЗ.Количество() > 1 И ТЗ[1].ПриоритетПоМагазинам = ТЗ[0].ПриоритетПоМагазинам Тогда
    Если ИгнорироватьОшибки Тогда
    Возврат ЗначениеПоУмолчанию; //Возвращаем, что значение не найдено.
    Иначе
    Р = ";
    Для Каждого КЗ ИЗ СтруктураПоиска Цикл
    Р = Р + КЗ.Ключ + " = " + КЗ.Значение + Символы.ПС;
    КонецЦикла;
    САП.ПечатьТЗ(ТЗ);
    ВызватьИсключение "При расчете коэффициента по структуре поиска: " + Р + " выявлена неоднозначность назначения, нужно исправить назначенные коэффициенты!" ;
    КонецЕсли;
    КонецЕсли;

    Найден = истина;
    Возврат ТЗ[0].Значение;
    КонецФункции
```
---
Часы или реактивный самолет?
Повторю вопрос:
Единственное, что интересно - во сколько раз ускорилось исполнение программы - по сравнению с первоначальными 40сек.
---
Уважаемый agrustny, коверкайте на здоровье мой никнейм и звание, но, пожалуйста, не приписывайте мне оценок, которые я не давал. Кроме того, я знаком с другими весьма достойными работами данного автора, чтобы так судить об этом коде.
---
Так, я не понял
Он размышлял об Эмпедокле,
Я же не просто так пишу Профессор, а оттого что ценю Ваш интеллект и эрудицию, проявляемую не только в использовании и популяризации математических методов, но и высоком культурном уровне
Читал Мюссе, ценил Массне,
Эльдорадович - это высокая оценка Ваших начинаний, так сказать алмазных залежей (в противопоставление всякой саже и графиту), поскольку Эльдорадо — мифическая южноамериканская страна из золота и драгоценных камней, и Вы происхождением как будто оттуда
И по зиме гулял в монокле,
Я считаю, что оценивать надо код, а не прежние заслуги автора, будь он хоть талантом гением! Amicus Plato, sed magis arnica Veritas! А Вы что пишите в последнем посте?! Автор - хороший, значит и код - замечательный...
А по весне носил пенсне
Странно, но Вы хотите чтобы все разговаривали как американские президенты, члены дипмиссий и прочие политиканы? Я так понял, что ускорение благодаря "помощи зала" достигнуто нехилое (хотя об этом сообщается весьма расплывчато), значит первоначальный код - существенно неоптимален. Имейте чувство юмора, как и автор (14), чтобы понять, что именно это саркастически было описано как гнилой. И улыбайтесь чаще!
---
1) ИгнорироватьОшибки лучше сделать отдельным параметром, передаваемым в функцию, чем постоянно тягать его в структуру-из структуры
2) и все-таки я не понял, зачем копировать структуру поиска, а не использовать оригинальную для передачи в следующий вызов функции, заменяя в ней значение одного-единственного поля.
3) вот это "//Удаляем то, что не подходит под период" - лучше сделать один раз для всей таблицы коэффициентов. Или сразу ее получать с учетом заданного периода.
---
А если попробовать сразу, заранее, подготовить массив всех возможных условий? Скажем, в какую-то ТЗ. Расположить их там таким образом:
Условие детальное
Условие общее
...
Особенно, если нужно все равно перебрать все вариант - то, возможно, скорость работы возрастет прилично.