15 мифов о платформе 1С

16.07.25

Разработка - Механизмы платформы 1С

Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?

В 2008 году я разработал собственный веб-клиент для платформы 1С:Предприятие. Его третья версия, которая появилась в 2015-м, оказалась экономически успешной. Последние девять лет на вопрос о том, чем занимается наша компания, я отвечаю: «Мы делаем сайты на 1С». Мы называем их веб-интерфейсами или веб-порталами. Визуально они выглядят как обычные сайты.

Пример нашего решения:

 

 

Внешне оно выглядит как обычный сайт. Его преимущество в том, что это интерфейс для заказа товаров дилерами и партнерами, работающий напрямую с 1С:Предприятие. Пользователи видят реальные остатки, актуальные номенклатурные списки, персональные цены и скидки – без ограничений, характерных для сайтов с отдельными СУБД и обменами. Такая интеграция часто невозможна в стандартных интерфейсах. Это ответ на вопрос, зачем создавать сайты на 1С.

В процессе создания собственного веб-клиента для 1С мы столкнулись с необходимостью оптимизации большого количества алгоритмов. Это в обычном интерфейсе 1С пользователи уже привыкли, что форма документа может открываться 5 секунд, а на запись требуется больше 10. Веб-интерфейсы пользователь воспринимает как обычный сайт, а к производительности сайтов предъявляются намного более жесткие требования: открытие страницы – менее чем за секунду, создание заказа – 2-3 секунды. Поэтому нам пришлось долго экспериментировать, чтобы среди нескольких алгоритмов выбрать наиболее быстродействующий. Сайт – это одна большая строка в формате html, которая заполнена данными, извлеченными из СУБД. Именно поэтому среди разобранных мифов будет много тем, связанных с обработкой строк и взаимодействием с базой данных.

 

Методология проверки мифов

 

Для тестирования была разработана внешняя обработка для демо-конфигурации «1С:Библиотека стандартных подсистем» (БСП). Она содержит 16 отдельных вкладок – по одной для каждого мифа. В рамках каждой вкладки представлены:

  • наименование проверяемого мифа,

  • код для тестирования утверждения,

  • кнопки запуска тестовых сценариев,

  • область вывода результатов замеров.

 

 

Разборы представлены в формате «Тезис -> Тестовый пример -> Подтверждение или опровержение -> Обоснование». В конце по каждому мифу я буду не только подтверждать или опровергать утверждение, но и объяснять, почему платформа работает именно так.

Часть информации была взята с сайтов разработчика платформы, в основном с its.1c.ru – этим источникам можно доверять однозначно. Другая часть – наши выводы. Они могут быть ошибочными. В случае обнаружения неточностей в методологии тестирования или интерпретации результатов мы открыты для дискуссии.

 

Миф 0. Код, написанный в одну строку, работает быстрее

 

Все знают об этом мифе. Код действительно работает быстрее. Алгоритм проверки:

Массив1 = Новый Массив;
Массив2 = Новый Массив;

Для Счетчик = 1 По 1000000 Цикл
Массив1.Добавить(Счетчик);
КонецЦикла;
Для Счетчик = 1 По 1000000 Цикл Массив2.Добавить(Счетчик); КонецЦикла;

Есть два массива, каждый из них заполняется миллионом значений в цикле. Функциональность циклов идентична, но первый написан в «человеческом» виде, а второй – в одну строку.

Результат следующий:

 

 

Код в одну строку действительно работает значительно быстрее – почти в 10 раз. Это объясняется особенностями алгоритма компиляции кода платформой 1С:Предприятие.

В процессе тестирования возникали вопросы: «А вдруг при первом запуске цикла платформа “разогревается”, происходит кэширование данных? Что будет, если поменять последовательность выполнения тестовых циклов местами?» Естественно, мы сделали дополнительные проверки. Однако результат показал: от перемены мест слагаемых результат не меняется.

Массив1 = Новый Массив;
Массив2 = Новый Массив;

Для Счетчик = 1 По 1000000 Цикл Массив2.Добавить(Счетчик); КонецЦикла;

Для Счетчик = 1 По 1000000 Цикл
Массив1.Добавить(Счетчик);
КонецЦикла;

 

Стоит отметить: в статье по каждому мифу демонстрируются только один итоговый результат. Но это не значит, что мы ограничились единственной попыткой. Все представленные результаты прошли многократную проверку.

 

 

Миф №0 подтвержден. Переходим к следующим.

 

Миф 1. Обфусцированный код работает быстрее

 

Это утверждение логично вытекает из мифа №0, поскольку обфусцированный код обычно содержит меньше строк.

Методика проверки

За основу взят алгоритм из мифа №0 (заполнение массива). Мы сделали его более «разлапистым», чтобы обфускатору было над чем поработать. В первом случае этот код содержит всего три строки после обфускации:

Массив1 = Новый Массив;
Массив2 = Новый Массив;

// Обфусцированный код с переносом строк
~0:___a=-1;~1:___a=1;~2:___a=1;~3:___a=-1;goto ~5;~4:старт=текущаяуниверсальнаядатавмиллисекундах();goto ~6;~5:старт=текущаяуниверсальнаядатавмиллисекундах();goto ~9:;~10:массив1.добавить(a*100000+а_*10000+a___*1000+a___*100+_a*10+__a);goto... ~27;~11:goto ~7;~12:___a=1;~13:___a=1;if ___a=-1 then goto ~17;endif;goto ~18;~14:;~1...
enddo;enddo;~28:___a=0;if 0=1 then goto ~37;endif;goto ~38;~29:___a=0;if 0<1 then goto ~36;endif;goto ~30;~30:~31:финиш=текущаяуниверсальнаядатамиллисекундах():goto...
Сообщить("Обфусцированный код в три строки, время выполнения, мсек: " + Строка(Финиш - Старт));

// Обычный код с переносом строк
Для Счетчик1 = 1 По 10 Цикл
Для Счетчик2 = 1 По 10 Цикл
Для Счетчик3 = 1 По 10 Цикл
Для Счетчик4 = 1 По 10 Цикл
Для Счетчик5 = 1 По 10 Цикл
Для Счетчик6 = 1 По 10 Цикл
Массив1.Добавить(Счетчик1*100000 + Счетчик2*10000 + Счетчик3*1000 + Счетчик4*100 + Счетчик5*10 + Счетчик6);
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;

// Обычный код без переноса строк
Для Счетчик1 = 1 По 10 Цикл Для Счетчик2 = 1 По 10 Цикл Для Счетчик3 = 1 По 10 Цикл Для Счетчик4 = 1 По 10 Цикл Для Счетчик5 = 1 По 10 Цикл Для Счетчик6 = 1 По 10

 

Выполняем замеры и видим, что обфусцированный код действительно работает быстрее, чем обычный код с переносами строк. Но мы дополнительно взяли обычный цикл в одну строку в качестве эталона. В результате мы видим, что он работает быстрее обфусцированного варианта.

 

 

Зачем вообще мы проверяли обфусцированный код? Дело в том, что чаще всего его используют для защиты собственных решений. Мы тоже вынуждены применять этот подход, потому что пиратство у нас, к сожалению, имеет место. Наши клиенты регулярно спрашивают: «Обфусцированный код обычно содержит больше операций, не увеличивает ли его использование время выполнения кода ваших решений? Ведь он должен работать медленнее». Нет, как видите, не увеличивает.

Мы решили еще немного оптимизировать этот алгоритм: обфусцированный код привели вручную к одной строке, после чего проверили, будет ли результат еще быстрее.

Массив1 = Новый Массив;
Массив2 = Новый Массив;

// Обычный код с переносом строк
Для Счетчик1 = 1 По 10 Цикл
Для Счетчик2 = 1 По 10 Цикл
Для Счетчик3 = 1 По 10 Цикл
Для Счетчик4 = 1 По 10 Цикл
Для Счетчик5 = 1 По 10 Цикл
Для Счетчик6 = 1 По 10 Цикл
Массив1.Добавить(Счетчик1*100000 + Счетчик2*10000 + Счетчик3*1000 + Счетчик4*100 + Счетчик5*10 + Счетчик6);
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;

// Обфусцированный код без переноса строк

~0:___a=-1;~1:___a=1;~2:___a=1;~3:___a=-1;goto ~5;~4:старт=текущаяуниверсальнаядатавмиллисекундах();goto ~6;~5:старт=текущаяуниверсальнаядатавмиллисекундах();goto

// Обычный код без переноса строк
Для Счетчик1 = 1 По 10 Цикл Для Счетчик2 = 1 По 10 Цикл Для Счетчик3 = 1 По 10 Цикл Для Счетчик4 = 1 По 10 Цикл Для Счетчик5 = 1 По 10 Цикл Для Счетчик6 = 1 По 10

 

Оказалось, что производительность действительно повысилась. В строках результатов №2 и №3 представлено сравнение обычного кода и обфусцированного: вы видите, что по умолчанию обфускация дает эффект ускорения выполнения. Но, тем не менее, обфусцированный код в одну строку работает медленнее, чем обычный код в одну строку. Причина этого вполне понятна: в обфусцированном коде больше операторов.

 

 

Поэтому мы считаем, что этот миф подтвержден, но с оговорками: по умолчанию обфусцированный код работает быстрее. Однако можно добиться того, что обычный код будет работать быстрее обфусцированного.

 

Миф 2. Функция СтрШаблон() быстрее, чем СтрЗамена()

 

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

Мы подумали: если функцию СтрШаблон() можно вызвать один раз, а функцию СтрЗамена() надо вызывать несколько раз, значит, СтрЗамена() должна работать значительно медленнее. Для проверки мы создали два функционально идентичных алгоритма: первый использует СтрШаблон(), второй – последовательность вызовов СтрЗаменить():

СтрокаШаблон = "Синтакс-Помощник -- средство, облегчающее разработку модулей. Основная задача Синтакс-Помощника...
| Для вызова Синтакс-Помощника используйте '%1'.
| Окно Синтакс-Помощника разделено на две части. Разделение может быть выполнено по вертикали...
| Окно содержит три закладки '%2', '%3' и '%4'. На первой размещается иерархический список...
| Текущее описание можно распечатать с помощью кнопки печати командной панели, расположенной...
| Если глава была открыта с использованием поиска (по индексу или по произвольному тексту)...
| Если в процессе просмотра выбирались несколько страниц, то с помощью команд '%7' и '%8'..."

C = Новый Массив;
C.Добавить("Справка -- Синтакс-Помощник");
C.Добавить("Содержание");
C.Добавить("Индекс");
C.Добавить("Поиск");
C.Добавить("Поиск в Синтакс-Помощнике");
C.Добавить("Найти текущий элемент в дереве");
C.Добавить("Переход вперед");
C.Добавить("Переход назад");

Для Счетчик = 1 По 10000 Цикл
СтрокаРезультат = СтрШаблон(СтрокаШаблон, C[0], C[1], C[2], C[3], C[4], C[5], C[6], C[7]);
КонецЦикла;

Для Счетчик = 1 По 10000 Цикл
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%1", C[0]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%2", C[1]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%3", C[2]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%4", C[3]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%5", C[4]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%6", C[5]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%7", C[6]);
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%8", C[7]);
КонецЦикла;

 

Результат: время выполнения вообще не различается.

 

 

Тогда возникла новая мысль: а что если поместить алгоритм заполнения в цикл? Количество строк кода уменьшится (было восемь отдельных вызовов СтрЗаменить(). Останется тоже восемь, но в более компактной форме). Ведь мы выяснили, что количество строк влияет на производительность.

СтрокаШаблон = "Синтакс-Помощник -- средство, облегчающее разработку модулей. Основная задача Синтакс-Помощника...
| Для вызова Синтакс-Помощника используйте '%1'.
| Окно Синтакс-Помощника разделено на две части. Разделение может быть выполнено по вертикали...
| Окно содержит три закладки '%2', '%3' и '%4'. На первой размещается иерархический список...
| Текущее описание можно распечатать с помощью кнопки печати командной панели, расположенной...
| Если глава была открыта с использованием поиска (по индексу или по произвольному тексту)...
| Если в процессе просмотра выбирались несколько страниц, то с помощью команд '%7' и '%8'..."
C = Новый Массив;
C.Добавить("Справка -- Синтакс-Помощник");
C.Добавить("Содержание");
C.Добавить("Индекс");
C.Добавить("Поиск");
C.Добавить("Поиск в Синтакс-Помощнике");
C.Добавить("Найти текущий элемент в дереве");
C.Добавить("Переход вперед");
C.Добавить("Переход назад");

Для Счетчик = 1 По 10000 Цикл
СтрокаРезультат = СтрШаблон(СтрокаШаблон, C[0], C[1], C[2], C[3], C[4], C[5], C[6], C[7]);
КонецЦикла;

Для Счетчик = 1 По 10000 Цикл
Для Счетчик2 = 0 По 7 Цикл
СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%" + Счетчик2, C[Счетчик2]);
КонецЦикла;
КонецЦикла;

 

Оказалось, влияние есть, но в обратную сторону. Когда мы поместили несколько СтрЗаменить() в цикл, время выполнения увеличилось вдвое. Это наводит на мысль, что дело не просто в количестве строк в коде, а в строках, связанных именно с циклическими операциями.

 

 

Мы провели дополнительный тест: оформили цикл с СтрЗаменить() в одну строку.

СтрокаШаблон = "Синтакс-Помощник -- средство, облегчающее разработку модулей. Основная задача Синтакс-Помощника...
| Для вызова Синтакс-Помощника используйте '%1'.
| Окно Синтакс-Помощника разделено на две части. Разделение может быть выполнено по вертикали...
| Окно содержит три закладки '%2', '%3' и '%4'. На первой размещается иерархический список...
| Текущее описание можно распечатать с помощью кнопки печати командной панели, расположенной...
| Если глава была открыта с использованием поиска (по индексу или по произвольному тексту)...
| Если в процессе просмотра выбирались несколько страниц, то с помощью команд '%7' и '%8'..."
C = Новый Массив;
C.Добавить("Справка -- Синтакс-Помощник");
C.Добавить("Содержание");
C.Добавить("Индекс");
C.Добавить("Поиск");
C.Добавить("Поиск в Синтакс-Помощнике");
C.Добавить("Найти текущий элемент в дереве");
C.Добавить("Переход вперед");
C.Добавить("Переход назад");

Для Счетчик = 1 По 10000 Цикл
СтрокаРезультат = СтрШаблон(СтрокаШаблон, C[0], C[1], C[2], C[3], C[4], C[5], C[6], C[7]);
КонецЦикла;

Для Счетчик = 1 По 10000 Цикл
Для Счетчик2 = 0 По 7 Цикл СтрокаРезультат = СтрЗаменить(СтрокаШаблон, "%" + Счетчик2, C[Счетчик2]); КонецЦикла;
КонецЦикла;

 

Результат сохранился на прежнем уровне – 560 миллисекунд.

 

 

Считаем, что данный миф не подтвержден: функция СтрШаблон() не быстрее, чем СтрЗамена(). При этом, код с несколькими вызовами в цикле выполняется значительно медленнее – это важное наблюдение. Можно предположить, что на уровне платформы функция СтрШаблон() использует несколько вызовов функции СтрЗаменить() в цикле.

 

Миф 3. Текстовый документ быстрее, чем переменная типа «Строка»

 

Логично предположить, что если текстовый документ специально создан для работы с большими объемами текста, значит, он должен быть эффективнее. Для проверки мы использовали код, который 10 000 раз добавляет новую строку в пустую переменную типа «Строка» и в пустой текстовый документ.

Для Счетчик = 1 По 10000 Цикл
СтрокаРезультат = СтрокаРезультат + Строка(Счетчик) + Символы.ПС;
КонецЦикла;

ТД = Новый ТекстовыйДокумент;
Для Счетчик = 1 По 10000 Цикл
ТД.ДобавитьСтроку(Строка(Счетчик));
КонецЦикла;

 

Результат замера: текстовый документ работал в 5 раз медленнее.

 

 

Мы предположили, что, возможно, 10 000 строк недостаточно для раскрытия потенциала текстового документа. Увеличили объем текста до 100 000 строк.

Для Счетчик = 1 По 100000 Цикл
СтрокаРезультат = СтрокаРезультат + Строка(Счетчик) + Символы.ПС;
КонецЦикла;

ТД = Новый ТекстовыйДокумент;
Для Счетчик = 1 По 100000 Цикл
ТД.ДобавитьСтроку(Строка(Счетчик));
КонецЦикла;

 

Результат не улучшился: текстовый документ по-прежнему значительно отставал.

 

 

При этом в относительном выражении производительность переменной типа «Строка» тоже ухудшилась, причем нелинейно: хотя количество строк увеличилось в 10 раз, текстовый документ замедлился в 100 раз, а работа со строкой – в 150 раз. Это показывает, что текстовый документ может быть чуть более оптимизированным, но все равно остается слишком медленным. Для работы с большими текстами мы рекомендуем использовать потоки. Повторили тот же тест, используя потоки вместо строки и текстового документа. Сначала проверили на 10 000 строк, затем – на 100 000.

Поток = Новый ПотокВПамяти;
ЗаписьТекста = Новый ЗаписьТекста(Поток);
Для Счетчик = 1 По 10000 Цикл
ЗаписьТекста.Записать(Строка(Счетчик) + Символы.ПС);
КонецЦикла;
ЗаписьТекста.Закрыть();
СтрокаРезультат = ПолучитьСтрокуИзДвоичныхДанных(Поток.ЗакрытьИПолучитьДвоичныеДанные());

Поток = Новый ПотокВПамяти;
ЗаписьТекста = Новый ЗаписьТекста(Поток);
Для Счетчик = 1 По 100000 Цикл
ЗаписьТекста.Записать(Строка(Счетчик) + Символы.ПС);
КонецЦикла;
ЗаписьТекста.Закрыть();
СтрокаРезультат = ПолучитьСтрокуИзДвоичныхДанных(Поток.ЗакрытьИПолучитьДвоичныеДанные());

 

Результаты стали значительно интереснее: 110 миллисекунд и 1 секунда соответственно.

 

 

Учитывая наше открытие о преимуществе однострочных циклов (миф №0), мы преобразовали код в однострочный формат и добавили тест для миллиона строк.

Поток = Новый ПотокВПамяти;
ЗаписьТекста = Новый ЗаписьТекста (Поток);
Для Счетчик = 1 По 10000 Цикл ЗаписьТекста.Записать(Строка(Счетчик) + Символы.ПС); КонецЦикла;
ЗаписьТекста.Закрыть();
СтрокаРезультат = ПолучитьСтрокуИзДвоичныхДанных (Поток. ЗакрытьИПолучитьДвоичныеДанные());

Поток = Новый ПотокВПамяти;
ЗаписьТекста = Новый ЗаписьТекста (Поток);
Для Счетчик = 1 По 100000 Цикл ЗаписьТекста.Записать(Строка(Счетчик) + Символы.ПС); КонецЦикла;
ЗаписьТекста. Закрыть();
СтрокаРезультат = ПолучитьСтрокуИзДвоичныхДанных (Поток. ЗакрытьИПолучитьДвоичныеДанные());

Поток = Новый ПотокВПамяти;
ЗаписьТекста = Новый ЗаписьТекста (Поток);
Для Счетчик = 1 По 100000 Цикл ЗаписьТекста.Записать(Строка(Счетчик) + Символы.ПС); КонецЦикла;
ЗаписьТекста.Закрыть();
СтрокаРезультат = ПолучитьСтрокуИзДвоичныхДанных (Поток. ЗакрытьИПолучитьДвоичныеДанные());

 

Получили совсем интересные результаты: 33 миллисекунды, 375 миллисекунд и 3760 миллисекунд. Четко видна линейная зависимость: при десятикратном увеличении объема данных время обработки возрастает в 10 раз, при стократном – в 100 раз.

 

 

Таким образом, миф опровергнут: текстовый документ не быстрее переменной типа «Строка». Сборка текста через текстовый документ требует больше времени. При этом потоки демонстрируют стабильную производительность без замедления при росте объемов.

Как работают потоки? Когда мне необходимо объяснить что-то сложное на примере чего-то простого, я стараюсь прибегать к примерам с автомобилями.

Представьте, что вас четыре человека и вам дали задачу переместить данные из СУБД в файловую систему. СУБД – это автомобиль с арбузами, а файловая система – это магазин. Вам необходимо переместить данные в магазин.

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

 

 

Получается, что человек забирает каждый новый арбуз, накапливая их в руках. В этом случае выборка каждого нового арбуза занимает все больше и больше времени, потому что «арбузы» складываются в оперативную память и занимают ее. Рано или поздно ресурсы сервера заканчиваются и наступает следующая ситуация:

 

 

Впечатлительным можно продолжать чтение: красная жидкость – это арбузный сок.

Чтобы такая ситуация не происходила, следует организовывать цепочку из людей. Каждый взял бы по арбузу: первый человек берет первый арбуз и передает его второму; второй человек передает первый арбуз третьему и так далее до места назначения. Таким образом работает поток:

 

 

Преимущества потокового подхода очевидны: в оперативной памяти всегда максимум четыре «арбуза», а выборка каждого следующего «арбуза» занимает столько же времени, сколько выборка первого «арбуза». Это доказано цифрами: 33 мс, 375 мс, 3760 мс. Вы можете обрабатывать неограниченное количество информации с предсказуемым линейным ростом времени выполнения алгоритма и без увеличения нагрузки на систему.

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

 

Миф 4. «ЗаполнитьЗначенияСвойств()» может работать медленно

 

Миф звучит так: «Функция ЗаполнитьЗначенияСвойств() может работать медленно, если в источнике намного больше ключей, чем в приемнике». Мы многократно запускали функцию, передавая в параметрах количество ключей в структуре-источнике и структуре-приемнике. При этом в приемнике значения свойств не заполнены (Неопределено), а в источнике содержат числа.

СтруктураИсточник = Новый Структура;
Для Счетчик = 1 По ИсточникКлючей Цикл
СтруктураИсточник.Вставить("Свойство" + Строка(Счетчик), Счетчик);
КонецЦикла;
СтруктураПриемникШаблон = Новый Структура;
Для Счетчик = 1 По ПриемникКлючей Цикл
СтруктураПриемникШаблон.Вставить("Свойство" + Строка(Счетчик), Неопределено);
КонецЦикла;

// Начало замера времени
Для Счетчик = 1 По 100000 Цикл
СтруктураПриемник = СтруктураПриемникШаблон;
ЗаполнитьЗначенияСвойств(СтруктураПриемник, СтруктураИсточник);
КонецЦикла;
// Окончание замера времени

 

Результаты показали, что при фиксированных 10 ключах в источнике время заполнения оставалось одинаковым независимо от количества ключей в приемнике (10, 100 или 500). Однако при увеличении количества ключей в источнике производительность заметно снижалась – с 500 ключами в источнике и всего 10 в приемнике время выполнения увеличилось в 6 раз.

 

 

У функции «СтрЗаполнить» есть третий необязательный параметр – «СписокЗаполняемыхСвойств». Если указать в нем максимальное количество свойств приемника, то время будет одинаковым для любого размера источника. Однако это время будет больше, чем без использования третьего параметра.

СтруктураИсточник = Новый Структура;
Для Счетчик = 1 По ИсточникамКлючей Цикл
СтруктураИсточник.Вставить("Свойство" + Строка(Счетчик), Счетчик);
КонецЦикла;
СтруктураПриемникШаблон = Новый Структура;
Для Счетчик = 1 По ПриемникамКлючей Цикл
СтруктураПриемникШаблон.Вставить("Свойство" + Строка(Счетчик), Неопределено);
КонецЦикла;
СписокСвойств = "";
КоличествоСвойств = Мин(ИсточникКлючей, ПриемникКлючей, 10);
Для Счетчик = 1 По КоличествоСвойств Цикл
СписокСвойств = СписокСвойств + "Свойство" + Счетчик;
Если Счетчик < КоличествоСвойств Тогда
СписокСвойств = СписокСвойств + ",";
КонецЕсли;
КонецЦикла;

// Начало замера времени
Для Счетчик = 1 По 100000 Цикл
СтруктураПриемник = СтруктураПриемникШаблон;
ЗаполнитьЗначенияСвойств(СтруктураПриемник, СтруктураИсточник, СписокСвойств)
КонецЦикла;
// Окончание замера времени

 

 

Миф считаем подтвержденным. Важно помнить: время работы функции значительно растет при увеличении числа свойств в источнике. Эту проблему можно решить с помощью третьего параметра «СписокЗаполняемыхСвойств». Однако его не рекомендуется применять, если количество ключей или свойств одинаковое, потому что это приведет к замедлению алгоритма.

 

Миф 5. «ЗначениеЗаполнено()» работает медленнее, чем проверка на пустое значение определенного типа

 

Проверяли следующим образом: создали два цикла, в первом взяли заполненное значение (например, число 10) и пустое значение (число 0). Смотрели, за какое время выполняется этот цикл. Во втором цикле проверяли то же самое с помощью функции «ЗначениеЗаполнено()». После множества замеров установили, что функция «ЗначениеЗаполнено()» выполняется стабильно медленнее прямой проверки на 1.5-2%.

Для Счетчик = 1 По 500000 Цикл
Если Значение <> ПустоеЗначение Тогда
КонецЕсли;
КонецЦикла;

Для Счетчик = 1 По 500000 Цикл
Если ЗначениеЗаполнено(Значение) Тогда
КонецЕсли;
КонецЦикла;

 

 

Технически миф подтвержден, но на практике мы продолжаем использовать «ЗначениеЗаполнено()» из-за ее универсальности, поскольку замедление незначительное. Дополнительно выяснилось: скорость проверки заполнения значений примитивных типов (строк, чисел) и скорость проверки заполнения ссылочных типов не различается, проверка на заполнение ссылки занимает столько же времени, сколько примитивный тип.

 

Миф 6. Для колонок таблицы значений необходимо указывать тип

Операции сортировки и отборов должны работать медленнее без указания типов колонок, что кажется логичным. Для проверки мы создали две таблицы значений с колонками «Строка», «Число» и «Ссылка». Для второй таблицы были заданы типы значений для колонок.

// Описание типов для колонок таблиц значений
КЧ = Новый КвалификаторыЧисла(12, 2);
КС = Новый КвалификаторыСтроки(20);
Массив = Новый Массив;
Массив.Добавить(Тип("Строка"));
ОписаниеТиповС = Новый ОписаниеТипов(Массив,, КС);
Массив.Очистить();
Массив.Добавить(Тип("Число"));
ОписаниеТиповЧ = Новый ОписаниеТипов(Массив,,, КЧ);
ТипСтр = "СправочникСсылка._ДемоНоменклатура";
ОписаниеТиповН = Новый ОписаниеТипов(ТипСтр);

// Таблица 1 - без определения типов колонок
Таблица1 = Новый ТаблицаЗначений;
Таблица1.Колонки.Добавить("КолонкаСтрока");
Таблица1.Колонки.Добавить("КолонкаЧисло");
Таблица1.Колонки.Добавить("КолонкаСсылка");

// Таблица 2 - с определением типов колонок
Таблица2 = Новый ТаблицаЗначений;
Таблица2.Колонки.Добавить("КолонкаСтрока", ОписаниеТиповС, "Строка", 20);
Таблица2.Колонки.Добавить("КолонкаЧисло", ОписаниеТиповЧ, "Число", 10);
Таблица2.Колонки.Добавить("КолонкаСсылка", ОписаниеТиповН, "Номенклатура", 30);

// Ссылки для заполнения таблиц
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
| _ДемоНоменклатура.Ссылка КАК Ссылка,
| _ДемоНоменклатура.Наименование КАК Наименование
|ИЗ
| Справочник. ДемоНоменклатура КАК ДемоНоменклатура";
РезультатЗапроса = Запрос.Выполнить();

 

Обе таблицы заполнили идентичными данными из базы: строковые значения в колонку «Строка», числа в «Число», ссылочные значения в «Ссылка».

Для Счетчик = 1 По 100 Цикл
Выборка.Следующий();
// Таблица 1
НоваяСтрока1 = Таблица1.Добавить();
НоваяСтрока1.КолонкаСтрока = "Строка " + Строка(Счетчик);
НоваяСтрока1.КолонкаЧисло = Счетчик;
НоваяСтрока1.КолонкаСсылка = Выборка.Ссылка;
// Таблица 2
НоваяСтрока2 = Таблица2.Добавить();
НоваяСтрока2.КолонкаСтрока = "Строка " + Строка(Счетчик);
НоваяСтрока2.КолонкаЧисло = Счетчик;
НоваяСтрока2.КолонкаСсылка = Выборка.Ссылка;
КонецЦикла;
Затем выполнили сортировку по каждой колонке и сделали отборы.

ОтборСтрока = Новый Структура("КолонкаСтрока", Таблица1[0].КолонкаСтрока);
ОтборЧисло = Новый Структура("КолонкаЧисло", Таблица1[0].КолонкаЧисло);
ОтборСсылка = Новый Структура("КолонкаСсылка", Таблица1[0].КолонкаСсылка);

// Начало замера времени
Для Счетчик = 1 По 1000 Цикл
Таблица1.Сортировать("КолонкаСтрока Убыв");
Таблица1.Сортировать("КолонкаЧисло Возр");
Таблица1.Сортировать("КолонкаСсылка Возр");
Таблица1.Сортировать("КолонкаСтрока Возр");
Таблица1.Сортировать("КолонкаЧисло Убыв");
Таблица1.Сортировать("КолонкаСсылка Убыв");
Таблица1.НайтиСтроки(ОтборСтрока);
Таблица1.НайтиСтроки(ОтборЧисло);
Таблица1.НайтиСтроки(ОтборСсылка);
КонецЦикла;
// Окончание замера времени

// Начало замера времени
Для Счетчик = 1 По 1000 Цикл
Таблица2.Сортировать("КолонкаСтрока Убыв");
Таблица2.Сортировать("КолонкаЧисло Возр");
Таблица2.Сортировать("КолонкаСсылка Возр");
Таблица2.Сортировать("КолонкаСтрока Возр");
Таблица2.Сортировать("КолонкаЧисло Убыв");
Таблица2.Сортировать("КолонкаСсылка Убыв");
Таблица2.НайтиСтроки(ОтборСтрока);
Таблица2.НайтиСтроки(ОтборЧисло);
Таблица2.НайтиСтроки(ОтборСсылка);
КонецЦикла;
// Окончание замера времени

 

 

Результат показал абсолютно одинаковое время выполнения операций.

 

 

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

Для Счетчик = 1 По 100 Цикл
Выборка.Следующий();
// Таблица 1
НоваяСтрока1 = Таблица1.Добавить();
НоваяСтрока1.КолонкаСтрока = "Строка " + Строка(Счетчик);
НоваяСтрока1.КолонкаЧисло = Счетчик;
НоваяСтрока1.КолонкаСсылка = Выборка.Ссылка;
// Таблица 2
НоваяСтрока2 = Таблица2.Добавить();
НоваяСтрока2.КолонкаСтрока = "Строка " + Строка(Счетчик);
НоваяСтрока2.КолонкаЧисло = Счетчик;
НоваяСтрока2.КолонкаСсылка = Выборка.Ссылка;
КонецЦикла;
Модифицированный код:

Для Счетчик = 1 По 100 Цикл
Выборка.Следующий();
// Таблица 1
НоваяСтрока1 = Таблица1.Добавить();
НоваяСтрока1.КолонкаСтрока = Счетчик;
НоваяСтрока1.КолонкаЧисло = Строка(Счетчик);
НоваяСтрока1.КолонкаСсылка = Выборка.Наименование;
// Таблица 2
НоваяСтрока2 = Таблица2.Добавить();
НоваяСтрока2.КолонкаСтрока = Счетчик;
НоваяСтрока2.КолонкаЧисло = Строка(Счетчик);
НоваяСтрока2.КолонкаСсылка = Выборка.Наименование;
КонецЦикла;

 

 

Мы попробовали в таблицы записать значение несоответствующего типа: в колонку «Строка» первой таблицы положили число, в колонку «Число» – ссылку, в колонку «Ссылка» добавили строку.

Результат:

  • В таблице №1 (где типы не заданы) данные сохранялись без преобразований.

  • В таблице №2 с заданными типами происходило автоматическое преобразование: строка в числовой колонке конвертировалась в число, число автоматически становилось строкой, ссылочные типы никак не преобразовывались.

 

 

Хотя указание типов колонок не ускоряет операции, они дают важное свойство: обеспечивают контроль данных через автоматическое приведение значений.

 

Миф 7. Запрос эффективнее, чем «НайтиПоКоду()»

 

Существует мнение, что получение ссылки на элемент с помощью запроса будет выполняться быстрее, чем с помощью функции «НайтиПоКоду()», особенно учитывая, что везде рекомендуется использовать запросы. Действительно, в практике в текстах модулей много мест, где используется запрос для получения ссылок.

Для проверки мы реализовали функционал поиска элемента с кодом «00001» двумя способами: через запрос и с помощью функции «НайтиПоКоду()». Результат оказался не в пользу запроса.

Для Счетчик = 1 По 3000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
| _ДемоНоменклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура
|ГДЕ
| _ДемоНоменклатура.Код = &Код";

Запрос.УстановитьПараметр("Код", "00-000001");
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Значение = Выборка.Ссылка;
КонецЦикла;
КонецЦикла;

Для Счетчик = 1 По 3000 Цикл
Значение = Справочники._ДемоНоменклатура.НайтиПоКоду("00-000001");
КонецЦикла;

 

 

У нас возникла гипотеза: возможно, само конструирование запроса в цикле отнимает много времени? Мы попробовали вынести конструктор запроса за пределы цикла, а внутри цикла только устанавливать параметр запроса. Да, это дало эффект ускорения, но все равно производительность запроса не превысила производительность функции «НайтиПоКоду()».

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
| _ДемоНоменклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура
|ГДЕ
| _ДемоНоменклатура.Код = &Код";
Для Счетчик = 1 По 3000 Цикл
Запрос.УстановитьПараметр("Код", "00-000001");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий().Цикл
Значение = Выборка.Ссылка;
КонецЦикла;
КонецЦикла;

Для Счетчик = 1 По 3000 Цикл
Значение = Справочники._ДемоНоменклатура.НайтиПоКоду("00-000001");
КонецЦикла;

 

 

На сайте its.1c.ru указано, что с точки зрения поиска объектов нет существенных отличий в реализации этих методов на уровне платформы. Методы менеджеров объектов удобны тем, что позволяют одной строкой произвести поиск. Для себя мы отмечаем, что конструктор запроса – более ресурсоемкая операция. Есть и положительный момент: конструктор запроса можно кэшировать, что дает ускорение в определенных сценариях использования.

 

Миф 8. Выборка из результата запроса эффективнее, чем выгрузка в таблицу значений

 

Часто озвучивается тезис: «Никогда не выгружайте результат запроса в таблицу значений, всегда используйте выборку». Для его проверки мы выполнили идентичный предыдущему тест двумя способами: в первом случае обошли результат запроса через выборку, во втором – выгрузили данные в таблицу значений. Результат показал, что выборка действительно эффективнее выгрузки в таблицу значений, причем разница существенная и заметная. Миф подтвержден.

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
| _ДемоНоменклатура.Ссылка КАК Ссылка,
| _ДемоНоменклатура.Наименование КАК Наименование
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
РезультатЗапроса = Запрос.Выполнить();

Для Счетчик = 1 По 5000 Цикл
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Значение = Выборка.Ссылка;
КонецЦикла;
КонецЦикла;

Для Счетчик = 1 По 5000 Цикл
Таблица = РезультатЗапроса.Выгрузить();
Для Каждого СтрокаТаблицы Из Таблица Цикл
Значение = СтрокаТаблицы.Ссылка;
КонецЦикла;
КонецЦикла;

 

 

Важное уточнение: согласно документации its.1c.ru при выполнении запроса вся считанная информация сразу передается на клиент и размещается в оперативной памяти (аналогия с «арбузами»). Выборка предпочтительнее, поскольку позволяет считывать данные порциями. Однако обратите внимание: в документации its.1c.ru речь идет не о выборке из результата запроса, а о выборке через менеджер объектов (например, Справочник.Номенклатура.Выбрать()). Именно такая выборка работает порционно. Результат обычного запроса всегда загружается в память целиком. Тем не менее, выборка из результата запроса остается быстрее выгрузки в таблицу значений.
 

Миф 9. СКД медленнее запроса

 

Для проверки сравнили два подхода:

  1. Выборка 100 элементов справочника «Номенклатура» через Систему компоновки данных (СКД);

  2. Та же выборка через запрос.

Для Счетчик = 1 По 100 Цикл
СхемаКД = Обработка.ПолучитьМакет("СКД_Номенклатура");
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(СхемаКД, Этаформа.УникальныйИдентификатор);
ИсточникНастроек = Новый ИсточникДоступныхНастроекКонтоновкиДанных (АдресВременногоХранилища);
ВыборОбъектовУсловияОтбора = Новый КомпоновщикНастроекКонтоновкиДанных;
ВыборОбъектовУсловияОтбора.Инициализировать(ИсточникНастроек);
ВыборОбъектовУсловияОтбора.ЗагрузитьНастройки(СхемаКД.НастройкиПоУполчанию);
Настройки = ВыборОбъектовУсловияОтбора.Настройки;
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпановкиДанных;
КомпоновщикМакета = Новый КонтоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКД, Настройки, ДанныеРасшифровки, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиданных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ДанныеРасшифровки);
ТЗРезультат = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(TЗРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецЦикла;

Для Счетчик = 1 По 100 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| _ДемоНоменклатура.Ссылка КАК Ссылка,
| _ДемоНоменклатура.ВерсияДанных КАК ВерсияДанных,
| _ДемоНоменклатура.ПометкаУдаления КАК ПометкаУдаления,
| _ДемоНоменклатура.Родитель КАК Родитель,
| _ДемоНоменклатура.ЭтоГруппа КАК ЭтоГруппа,
| _ДемоНоменклатура.Код КАК Код,
| _ДемоНоменклатура.Наименование КАК Наименование,
| _ДемоНоменклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| _ДемоНоменклатура.НаОсновномСкладе КАК НаОсновномСкладе,
| _ДемоНоменклатура.СкрытыйРеквизит КАК СкрытыйРеквизит,
| _ДемоНоменклатура.ФайлКартинки КАК ФайлКартинки,
| _ДемоНоменклатура.ГруппаДоступа КАК ГруппаДоступа,
| _ДемоНоменклатура.Цена КАК Цена,
| _ДемоНоменклатура.СтранаПроисхождения КАК СтранаПроисхождения,
| _ДемоНоменклатура.Штрихкод КАК Штрихкод,
| _ДемоНоменклатура.Артикул КАК Артикул,
| _ДемоНоменклатура.КодОКВЭД КАК КодОКВЭД,
| _ДемоНоменклатура.КодТНВЭД КАК КодТНВЭД,
| _ДемоНоменклатура.НаименованиеДляПечати КАК НаименованиеДляПечати,
| _ДемоНоменклатура.Комментарий КАК Комментарий,
| _ДемоНоменклатура.КомментарийЯзык1 КАК КомментарийЯзык1,
| _ДемоНоменклатура.КомментарийЯзык2 КАК КомментарийЯзык2,
| _ДемоНоменклатура.НаименованиеЯзык1 КАК НаименованиеЯзык1,
| _ДемоНоменклатура.НаименованиеЯзык2 КАК НаименованиеЯзык2,
| _ДемоНоменклатура.Предопределенный КАК Предопределенный,
| _ДемоНоменклатура.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
ТЗРезультат = Результат.Выгрузить();
КонецЦикла;

 

Результат оказался категорически не в пользу СКД – запрос выполнился более чем в 10 раз быстрее. Миф подтвержден.

 

 

Однако отказываться от СКД не стоит: во многих случаях она предоставляет возможности, которые через запросы реализовать значительно сложнее или вовсе невозможно.

 

Миф 10. Обработка коллекции объектов в транзакции выполняется быстрее, чем без транзакции

 

Проверяли на выборке элементов справочника «Номенклатура»: модифицировали комментарии и записывали изменения дважды – с транзакцией и без нее. Результат показал, что обработка в транзакции действительно выполняется быстрее. Миф подтвержден.

ТекстКомментария = "ТекущаяДатаСеанса() = " + ТекущаяДатаСеанса();

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
| _ДемоНоменклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура
|ГДЕ
| _ДемоНоменклатура.ЭтоГруппа = ЛОЖЬ";
РезультатЗапроса = Запрос.Выполнить();

НачатьТранзакцию();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ДемоНоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДемоНоменклатураОбъект.Комментарий = ТекстКомментария;
ДемоНоменклатураОбъект.Записать();
КонецЦикла;
ЗафиксироватьТранзакцию();

Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ДемоНоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДемоНоменклатураОбъект.Комментарий = ТекстКомментария;
ДемоНоменклатураОбъект.Записать();
КонецЦикла;

 

 

За счет чего это происходит? Основной эффект транзакций при создании/изменении/удалении данных – замена множества мелких операций с файловой системой на одну крупную. Вместо 100 отдельных обращений к файловой системе с записью элементов выполняется одна групповая операция. Однако важно помнить: применение транзакции – это тоже лишний алгоритм (аналогично конструктору запроса). Объявление транзакции отнимает время. При слишком малом объеме данных эффект нивелируется, а при чрезмерно большом – получится, что парней раздавило арбузами. Поэтому для каждой задачи необходимо подбирать оптимальный размер порции данных для одной транзакции.

 

Миф 11: Файловая база медленнее клиент-серверной

 

Проверяли на ненагруженном компьютере в идентичных условиях (стандартные настройки сервера и платформы). Код из мифа №10 запускали параллельно в файловой и клиент-серверной базе. Результат: файловая база работала заметно быстрее.

ТекстКомментария = "ТекущаяДатаСеанса() = " + ТекущаяДатаСеанса();

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
| _ДемоНоменклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.__ДемоНоменклатура КАК __ДемоНоменклатура
|ГДЕ
| _ДемоНоменклатура.ЭтоГруппа = ЛОЖЬ";
РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ДемоНоменклатураОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДемоНоменклатураОбъект.Комментарий = ТекстКомментария;
ДемоНоменклатураОбъект.Записать();
КонецЦикла;

 

 

Дополнительная проверка по предыдущим мифам показала стабильное преимущество файловой базы, кроме мифа №6 – клиент-серверный вариант там всегда был быстрее.

 

 

Миф не подтвержден, но с оговорками. Клиент-серверный вариант подразумевает выполнение дополнительных действий на пути данных из базы к пользователю Устанавливается дополнительное программное обеспечение. Это замедляет время работы клиент-серверной базы. Но в то же время данное ПО ускоряет клиент-серверный вариант. Все зависит от условия использования.

Вернемся к нашей метафоре с парнями. На этот раз группа друзей планирует поездку на юг. Представим, что легковая машина – это файловая база данных. Автобус же символизирует клиент-серверный вариант, который изначально предназначен для одновременной работы большого количества пользователей. Однако, когда в поездке участвуют всего два человека, автобус вынужден везти все свое лишнее железо (дополнительное ПО) независимо от необходимости в нем. Поэтому парни в машине, прокладывая маршрут, радостно замечают: «О, класс, мы доедем за 20 часов!». Парни в автобусе, выполнив те же расчеты, констатируют: «Мы доедем за 24 часа». В итоге обе группы благополучно прибывают на место, и у всех все складывается отлично.

Через год условия немного меняются: теперь в каждой группе по четыре человека. Парни в легковой машине (файловой базе) по-прежнему добираются за 20 часов. Группа в автобусе (клиент-сервер) – также за 24 часа.

 

 

Но у каждой системы есть свой предел возможностей. Этот предел проявляется при шестерых участниках. Шесть человек в машине начинают толкаться локтями, им становится тесно и некомфортно. Один из пассажиров говорит: «Ребята, срочно нужно остановиться – требуется перепровести документы». Пока он выполняет эту задачу, остальные вынуждены бездействовать. В результате обе группы прибывают одновременно – за 24 часа. Но уже заметна разница в комфорте: в автобусе просторно, а в машине – крайне тесно.

 

 

Теперь представим, что в базе одновременно работает 50 пользователей. Парни в автобусе спокойно рассаживаются по местам и без проблем продолжают путь. А вот группа в легковой машине (файловой базе) сталкивается с катастрофической ситуацией.

 

 

Впечатлительные могут не волноваться: красная жидкость на изображении – это антифриз, ни один человек не пострадал.

Поэтому, если вам объективно не требуется клиент-сервер и вы от него не зависите (например, у вас всего три постоянных пользователя) – смело работайте в файловой базе. Безусловно, у клиент-серверного решения есть определенные преимущества, но не стоит его внедрять, когда в нем нет реальной необходимости. Мы же не ездим по городу на автобусе каждый день.

 

Миф 12. Внешние обработки медленнее встроенных

 

Проверяли на примере тестовой внешней обработки: сначала запустили ее через «Файл ? Открыть», затем встроили в конфигурацию. Выполнили идентичный код для внешней и встроенной версий. Результат показал, что внешние обработки работают медленнее встроенных. Миф подтвержден.

Обработка1 = РеквизитФормыВЗначение("Объект");
Результат = Обработка1.Миф12Проверка();

Обработка2 = Обработки.ПятнадцатьИмфовОПлатформе1С.Создать();
Результат = Обработка2.Миф12Проверка();

Функция Миф12Проверка() Экспорт

Массив1 = Новый Массив;

Для Счетчик1 = 1 По 10 Цикл
Для Счетчик2 = 1 По 10 Цикл
Для Счетчик3 = 1 По 10 Цикл
Для Счетчик4 = 1 По 10 Цикл
Для Счетчик5 = 1 По 10 Цикл
Для Счетчик6 = 1 По 10 Цикл
Массив1.Добавить(Счетчик1*100000
+ Счетчик2*10000
+ Счетчик3*1000
+ Счетчик4*100
+ Счетчик5*10
+ Счетчик6);
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;

Возврат Массив1;

КонецФункции

 

 

Этот факт также официально признан компанией 1С. Причина в компиляции: модуль, встроенный в конфигурацию, компилируется однократно при инициализации для всех пользователей (точный уровень – серверный или процессный – не уточняется). Мы тестировали только время выполнения для одного пользователя. Кроме времени выполнения, есть также показатель – загрузка процессора. Компания 1С проводила замеры в условиях, приближенных к реальным: время выполнения увеличивается в 1,5 раза (~59%), а загрузка процессора – почти в 2,5 раза. Поэтому не рекомендуется выносить во внешние обработки функционал, активно используемый многими пользователями или вызываемый очень часто.

 

Миф 13. Вызов функции «&НаСервере» из функции «&НаСервере» инициирует вызов сервера

 

Некоторые полагают, что вызов серверной функции из другой серверной функции увеличивает счетчик вызовов сервера. Проверили с помощью кода: количество вызовов сервера действительно не увеличивается. Однако заметили, что при разбивке кода на две функции время выполнения возросло. Возможно, это связано с особенностями компиляции циклов платформой. Миф не подтвержден.

 

Процедура Миф13ПроверкаНаСервере()

Для Счетчик = 1 По 5000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| _ДемоНоменклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
КонeцЦикла;

КонeцПроцедуры

Процедура Миф13Проверка1НаСервере()

Для Счетчик = 1 По 5000 Цикл
Миф13Проверка1НаСервереБезКонтекста();
КонeцЦикла;

КонeцПроцедуры

Процедура Миф13Проверка1НаСервереБезКонтекста()

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| _ДемоНоменклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();

КонeцПроцедуры

 

 

 

 

Вызов серверной функции из серверной функции не создает новый вызов сервера. Но функционально идентичный код, написанный в одной функции, может выполняться быстрее, чем разбитый на несколько функций.

 

Миф 14. Получение представления объекта в запросе замедляет его выполнение

 

Использование свойства «Представление» или функции «Представление()» вместо объекта «Наименование» замедляет запрос. Проверили с помощью четырех идентичных циклов:

  1. Выбор ссылки;

  2. Выбор «Наименование»;

  3. Выбор «Представление»;

  4. Выбор через «Представление()».

Результат: использование свойства «Представление» незначительно замедляет запрос по сравнению с «Наименование», а функция «Представление()» – значительно. Миф подтвержден.

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| _ДемоНоменклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
КонецЦикла;

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ"
| _ДемоНоменклатура.Наименование КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
КонецЦикла;

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ"
| _ДемоНоменклатура.Представление КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
КонецЦикла;

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ"
| ПРЕДСТАВЛЕНИЕ(_ДемоНоменклатура.Ссылка) КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
КонецЦикла;

 

 

Эксперименты показывают, что ручное формирование представления путем конкатенации разных полей с данными объекта иногда вдвое быстрее использования встроенного свойства или функции.

 

Миф 15. Использование представления объектов в коде замедляет его выполнение

 

К предыдущему тесту добавили выгрузку результата запроса в таблицу значений. Результат: использование «Представление» потребовало в десятки раз больше времени. Миф подтвержден.

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| _ДемоНоменклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
ТЗРезультат = Результат.Выгрузить();
КонецЦикла;

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ"
| _ДемоНоменклатура.Наименование КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
ТЗРезультат = Результат.Выгрузить();
КонецЦикла;

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ"
| _ДемоНоменклатура.Представление КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
ТЗРезультат = Результат.Выгрузить();
КонецЦикла;

Для Счетчик = 1 По 1000 Цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ"
| ПРЕДСТАВЛЕНИЕ(_ДемоНоменклатура.Ссылка) КАК Номенклатура
|ИЗ
| Справочник._ДемоНоменклатура КАК _ДемоНоменклатура";
Результат = Запрос.Выполнить();
ТЗРезультат = Результат.Выгрузить();
КонецЦикла;

 

 

Согласно its.1c.ru:

  • Для выборки данных предпочтительнее «Наименование» (если не требуется расшифровка);

  • При выводе в табличный документ происходит замедление работы системы в десятки раз из-за вызова менеджеров объектов (включая возможные переопределения «Представления()»);

  • Аналогичный эффект наблюдается для объектов «ТаблицаЗначений» и «ДеревоЗначений».

Как только вы выгружаете представление из запроса в таблицу значений, операция потребует непропорционально много времени.

 

*************

Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TECH EVENT.

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Механизмы платформы 1С Работа с интерфейсом Программист Стажер 1С v8.3 Бесплатно (free)

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    10112    bayselonarrend    126    

63

Механизмы платформы 1С WEB-интеграция Программист 1С v8.3 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    16114    dsdred    77    

125

Механизмы платформы 1С Программист Стажер 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    18134    bayselonarrend    22    

168

Механизмы платформы 1С Программист Стажер 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    10246    dsdred    22    

84

Механизмы платформы 1С Программист Стажер 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    38661    YA_418728146    35    

75
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. aximo 2394 16.07.25 13:51 Сейчас в теме
Познавательно. Элемент 1С конкурент или нет?
TitanLuchs; +1 1 Ответить
2. TitanLuchs 554 16.07.25 13:53 Сейчас в теме
(1) Конкурент, но области пересечения ареалов у нас очень небольшие. Локтями не толкаемся, значительно на бизнес друг друга не влияем.
3. gybson 16.07.25 14:26 Сейчас в теме
Я правильно понимаю, что все это со включенной отладкой?
NeLenin; WarAn; TitanLuchs; +3 Ответить
7. TitanLuchs 554 16.07.25 15:24 Сейчас в теме
(3) Тестирование выполнялось на новом сервере со свежеустановленной платформой на файловой базе. Конфигуратор был открыт всегда, база запускалась из конфигуратора клавишей F5, соответственно, отладка была включена.
Там, где для тестирования был необходим клиент-серверный вариант, отладка на сервере также была включена.
10. gybson 16.07.25 15:36 Сейчас в теме
(7) Ну тогда это очередная статья про накладные расходы на отладку :(
NeLenin; JohnyDeath; zqzq; maksa2005; WarAn; dabu-dabu; xnd; dsdred; coollerinc; gigabyte_artur; G.Shatrov; BaphoBush; Sashares; awk; +14 Ответить
11. TitanLuchs 554 16.07.25 15:37 Сейчас в теме
(10) Напишите, как необходимо протестировать, сделаем
12. gybson 16.07.25 15:43 Сейчас в теме
(11) без отладки
это будет без замера производительности, но так обычно и делают, через ТекущаяУниверсальнаяДатаВМиллисекундах()
dsdred; gigabyte_artur; +2 Ответить
13. TitanLuchs 554 16.07.25 15:44 Сейчас в теме
(12) В файловой как проверять, так, как и раньше, или без конфигуратора?
14. gybson 16.07.25 16:13 Сейчас в теме
(13) без конфигуратора
TitanLuchs; +1 Ответить
27. RustIG 1900 17.07.25 10:15 Сейчас в теме
(13) добрый день! а зачем собственно файловую проверять? вы сайт на файловых базах делаете разве?
изначально была цель - максимально приблизить 1с на сайте к самой быстрой работе....
на файловых базах при увеличении пользователей начинаются котовасии независимо от оптимизации кода...
NeLenin; EvgeniyOlxovskiy; +2 Ответить
39. TitanLuchs 554 17.07.25 16:45 Сейчас в теме
(27) Сайты почти в 100% случаев работают на клиент-серверных базах. Проверяли в том числе и файловую, поскольку алгоритмы используем не только при разработке веб-интерфейсов, а многие мелкие клиенты работают на файловых базах.
94. nickperel 5 03.08.25 02:30 Сейчас в теме
(11)
Вы все методологически правильно протестировали. Вы не сравниваете режимы запуска сервера. Про отладку пишут ради того чтобы написать.
Где - то на ИТС есть проценты влияния, но они небольшие. То есть без отладки как-то изменяться времена тестов, но одновременно у всех вариантов тестироваания на одну величину. Может быть разную при разных способах измерения, но на одну. И это не важно для соотношений результатов.
4. Alxby 1137 16.07.25 14:30 Сейчас в теме
Для первых двух мифов не помешало бы указать влияние режима отладки на время выполнения :)
NeLenin; zqzq; dabu-dabu; dsdred; gigabyte_artur; TitanLuchs; +6 Ответить
5. Alxby 1137 16.07.25 14:30 Сейчас в теме
(4) ... не только я обратил на это внимание)
6. gybson 16.07.25 14:36 Сейчас в теме
(5) на самом деле почти все. Т.е., тот же "найти по коду" и запрос это тоже количество строк разное
8. RocKeR_13 1445 16.07.25 15:32 Сейчас в теме
А запись с/без транзакций сравнивали на MS SQL и PostgreSQL?)
TitanLuchs; +1 Ответить
9. TitanLuchs 554 16.07.25 15:33 Сейчас в теме
(8) Проверяли только на MS SQL
17. RocKeR_13 1445 16.07.25 17:36 Сейчас в теме
(9) Там тоже разница налицо, попробовал)
Прикрепленные файлы:
user2073904; TitanLuchs; +2 Ответить
15. awk 745 16.07.25 17:16 Сейчас в теме
(0) Какая методология замера? База какая? Отладка включена? Без данных ответов статья ни о чем не говорит.
16. seevkik 10 16.07.25 17:26 Сейчас в теме
Добавлю свои пять копеек:
Миф 0, 1, 2(вторая часть) - Необходимо отключить отладку на сервере.
Миф 3. Раз до потока в памяти дошли, то могли бы и с конкатенацией массива сравнить.
Миф 7. Нужно попробовать без «УстановитьПараметр» в цикле так как установкой параметра вы добавляете еще одну операцию (относительно НайтиПоКоду). Предполагаю, что разница будет в пределах погрешности.
Миф 8. Опять та же проблема - выгрузка в ТЧ и обход этой таблицы это две разных операции. Логично здесь сравнивать выборку и выгрузку без обхода ТЧ (не забываем про отладку).
Миф 11. Выборка первых 100 не релевантна. Попробуйте что-то немного сложнее, например, еще парочку соединений по индексируемым и неиндексируемым полям.
Миф 13. В целом логично, но разброс даже так слишком большой из-за отладки.
kuzyara; JohnyDeath; zqzq; dhurricane; +4 Ответить
40. TitanLuchs 554 17.07.25 16:49 Сейчас в теме
(16) "Нужно попробовать без «УстановитьПараметр» в цикле так как установкой параметра вы добавляете еще одну операцию" - это понятно, но какой смысл выполнения одного и того же запроса в цикле без изменения его параметров? Тогда всегда будет один и тот же результат. Но можно проверить и вариант с установкой параметра за пределами цикла, посмотрим, что изменится.
65. seevkik 10 18.07.25 12:43 Сейчас в теме
(40) Пересмотрел миф 7.
Смысл мифа не «проверить скорость установки параметров», а «сравнить скорость выполнения запроса».
Возможно вообще не релевантно использовать «НайтиПоКоду» так как он может скешировать результат (но не факт).
18. user612295_death4321 16.07.25 18:28 Сейчас в теме
Миф 11: Файловая база медленнее клиент-серверной - этот миф широко раскрывается не на пустых демо-базах, а базах с заполненными данными 4-12 ГБ.
unknown181538; +1 Ответить
28. RustIG 1900 17.07.25 10:18 Сейчас в теме
(18) при 30 Гб на 15 пользователей - файловая даже очень быстра....
то есть 4-12 Гб такой объем влияет , когда железо сервера совсем древнее
33. user612295_death4321 17.07.25 13:05 Сейчас в теме
(28) Не могу согласиться. Имею полностью альтернативный опыт, когда на железе уровня i9-9900k / 64 ram / NVMe линейки Samsung EVO на файловой базе запросы выполняются долго, перекидываешь этот же самый ДТшник в клиент-серверный SQL Server без каких либо модификаций и оптимизаций (на этом же самом железе) и она начинает летать.

А вообще если у Вас в продакшене файловая БД на 30 ГБ с 15 пользователями, я хз, езжайте в Сочи и ставьте на zero.
Dimanchik00; +1 Ответить
34. RustIG 1900 17.07.25 13:18 Сейчас в теме
(33) база на обычных формах УТ 10.3, плюс 15 торговых агентов на мобильных Агент+ кидают заказы в УТ, плюс обработка от Контур.Диадок - для отправки ЭДО....
полет нормальный был, дошли до критического размера одной таблицы из этой базы и перешли на С-ку-эль.
45. RocKeR_13 1445 17.07.25 17:13 Сейчас в теме
(34) Ну УТ 10 - это вообще не показатель: попробуйте лучше какой-нибудь 1С:Общепит. Вот там в файловом варианте на базе в 25 Гб 3-4 пользователя весьма некомфортно работают, даже при условии, что база опубликована на веб-сервере)
56. RustIG 1900 17.07.25 17:47 Сейчас в теме
(45) общепит это отраслевая, многие отраслевые, которые я видел - ужасны , разработчики так себе. Я общепит однажды ковырял, код ужасен.
57. RocKeR_13 1445 17.07.25 17:56 Сейчас в теме
(56) Да на самом деле даже УТ 11 тоже тяжело идет в файловом варианте. Сейчас в файловом варианте уже для 2-3 пользователей она начинает шевелиться только после публикации на веб-сервере. Даже Розницу 2.3 в одном магазине на 2 кассы + РМ менеджера пришлось переводить на мини-сервер + PostreSQL уже после 3 лет работы. Благо мини-сервер по цене сопоставим с качественной сверткой базы, а база тем временем спустя 2 года все еще летает без сверток и обновления железа)
unknown181538; Жолтокнижниг; +2 Ответить
58. RustIG 1900 17.07.25 19:22 Сейчас в теме
(57) ага, на управляемых формах не смогли сделать для файловых баз адекватные приложения, возможно проблемы из-за механизма длительных операций, которые у каждого пользователя запускаются
75. muskul 23.07.25 03:41 Сейчас в теме
(34) даже бп 2.0 на оборотке за год умирала в файловой
95. nickperel 5 03.08.25 02:44 Сейчас в теме
(33) Все правильно. На СУБД работает "подъем" страниц с диска в память и работает оптимизатор запросов. После накопления статистики выполнения планов - еще лучше.
43. TitanLuchs 554 17.07.25 17:03 Сейчас в теме
(18) Сделаем еще один тест на 10-гиговой базе, на 200-гиговой.
50. user612295_death4321 17.07.25 17:29 Сейчас в теме
(43) я не принуждаю, я просто поделился опытом из своей практики :)

Помоему как я только не издевался над той файловой базой, включая разные ТиИ, счастья по скорости не наступило) Тоже была УТшка в р-не 12+ ГБ, но бустануть её смог только клиент-сервер.
TitanLuchs; +1 Ответить
51. TitanLuchs 554 17.07.25 17:31 Сейчас в теме
(50) Нет, мы сделаем, поскольку подобные запросу поступили еще несколько раз, и самим интересно.
19. PerlAmutor 160 16.07.25 20:19 Сейчас в теме
Самые главные "мифы" кроются в запросах к БД и блокировках. На моей памяти немного было алгоритмов которые мне приходилось оптимизировать и в большинстве случаев основная беда была в циклах, которых могло бы и не быть с грамотным использованием методов для массовых обработок данных. Часто это просто плохая реализация, когда вместо нормального запроса используют множество вызовов циклов, которые вызывают функции содержащие другие циклы и т.д.
А вот что меня реально удивило как-то, так это прибавка скорости когда все значения перечисления помещаются в Соответствие вместо непосредственного использования ни как "Перечисления.ИмяПеречисления.Значение", ни как ПредопределенноеЗначение("Перечисление.ИмяПеречисления.Значение") (этот самый медленный так как за каждым значением лезет на сервер).

В общем да, хотелось бы увидеть мифы чисто про конструкции запросов. Например ТИПЗНАЧЕНИЯ()=ТИП() быстрее/медленнее "Т.Поле Ссылка Документ.РеализацияТоваровУслуг", "1=1" быстрее/медленнее чем "Истина", "ИЛИ" быстрее/медленнее "В()", предварительная выборка во временную таблицу и соединение с ней быстрее/медленнее чем ВНУТРЕННЕЕ СОЕДИНЕНИЕ сразу с обеими таблица и т.д.
user2073904; TitanLuchs; RustIG; VyacheslavShilov; ixijixi; +5 Ответить
44. TitanLuchs 554 17.07.25 17:08 Сейчас в теме
(19)
ни как ПредопределенноеЗначение("Перечисление.ИмяПеречисления.Значение") (этот самый медленный так как за каждым значением лезет на сервер)

На ИТС сказано, что обращение к серверу выполняется только первый раз, а затем значение кэшируется и хранится на клиенте: https://its.1c.ru/db/v8std/content/443/hdoc.
UPD: проверил в СП - там тоже так написано: "Результат выполнения кэшируется при первом обращении до изменения конфигурации или версии платформы."
20. PaTRiaRX 16.07.25 20:41 Сейчас в теме
КонтоновщикМакетаКомпоновкиДанных

Typo.
21. dehro 12 16.07.25 20:42 Сейчас в теме
НайтиПоКоду и Запрос сравнивались некорректно.
Смысл запрос имеет есть есть массив кодов (штук так несколько), тогда один запрос будет быстрее, чем несколько поисков по коду.
А тут сравнивали два одинаковых запроса: один уже скомпилирован, а второй интерпретируется каждый раз.
41. TitanLuchs 554 17.07.25 16:54 Сейчас в теме
(21) У нас задача как раз в этом и состояла: проверить, что быстрее при получении одного значения, поскольку широко распространено мнение, что запрос всегда лучше. Понятно, что если необходимо получить массив значений или объединить данные из нескольких источников, запрос скорее всего будет эффективнее.
22. t278 58 17.07.25 04:02 Сейчас в теме
НайтиПоКоду и Запрос
а если в строчку код будет?
23. user1832003 59 17.07.25 04:07 Сейчас в теме
про 8 миф речь вообще не об этом в мифе должна быть. Изначально речь о том, получить таблицу быстрее путем выгрузить(), а не созданием таблицы и обходом выборки с заполнением построчно через ЗАполнитьЗначенияСвойств(). Так что миф изначально не верен и именно для этого сценария Выгрузить() намного быстрее

9 миф бред. Скд выполняет запрос, а потом делает вывод. А запрос только делает запрос. тут все логично.

про 10 не видел ничего подобного на итсе, значит этот вывод автора и он не выглядит как верный. Транзакция делает пометку в журнале типо транзакция начала и если целостность данных нарушена, то идет от-кат(почему инфостарт меняет слово на звездочку?) всех действий с бд после этой пометки. Там не выполняется никаких особенных способов записи или еще чего.

по 12 мифу. именно поэтому все тесты предыдущих 11 мифов максимально бесполезны на внешней обработке и должны были быть сделаны на встроенной в конфу форме или обработке

14 абсолютно логично. Для представления вызывается соответствующий обработчик для каждого объекта. Платформенный или переопределенный не важно. А в запросе тупо берешь реквизит таблицы и все ок.

вывод: исходя из 12 мифа все результаты статьи мусор. Надо переделывать путем вклинивания обработки в конфу.
42. TitanLuchs 554 17.07.25 16:56 Сейчас в теме
(23) "по 12 мифу. именно поэтому все тесты предыдущих 11 мифов максимально бесполезны на внешней обработке и должны были быть сделаны на встроенной в конфу форме или обработке" - вывод неверный, все тестирование выполнялось на обработке, встроенной в конфигурацию. Проверка на внешней обработке делалась только в упомянутом выше мифе.
60. user1832003 59 18.07.25 01:51 Сейчас в теме
(42) а платформа какая использовалась?
24. zakharov_yuri 43 17.07.25 07:17 Сейчас в теме
Хорошая статья. Познавательно.
JOJ73; TitanLuchs; +2 Ответить
25. muskul 17.07.25 09:36 Сейчас в теме
Как то тестировал остатки через запрос и через платформенные штуки. штуки оказались тоже быстрей.
26. KDL75 59 17.07.25 10:10 Сейчас в теме
Спасибо, статья полезная, но надо все тесты делать без отладчика.
TitanLuchs; +1 Ответить
29. RustIG 1900 17.07.25 10:25 Сейчас в теме
(0) добрый день! привык, что вы Цифровой КОТ... в этой статье ни разу не упомянули....
Вопрос такой: а как все эти улучшения ускорили открытие формы в 1 секунду (вместо 5 секунд), и проведение документа в 1 секунду (вместо 10 секунд).
Судя по тому, что я вижу в типовых конфигурациях, там половина кода можно удалить - при открытии, а при проведении - тоже половина проверок можно удалить....Да и при работе с каталогом для заказа - мы не работаем напрямую с документом Заказ - то есть открытия нет, проведение отложенное....
Вот такую парадигму , кстати, можно организовать в типовых 1с - так сказать насоздавать рабочие столы для каждой роли в процессе, чтобы было быстрее работать....
ПС. один час продуктивной работы потерян... :( пока читал, вчитывался, думал и вдумывался.... :(
эх, 1с, сколько в тебе ненужного .....рождаются мифы, потом вокруг мифов отделы анализа непонятного/ неочевидного/неоптимального возникают.... продолжаются обсуждения....а время утекает.....что осталось в голове? ....у меня лично - про НайтиПокоду() использовал и буду использовать, использовать СКД для ускорения? контейнер работы с запросами для интерактива - вот это СКД - зачем его так программно использовать в цикле? как это приблизит нас к созданию сайта?....
:(
47. TitanLuchs 554 17.07.25 17:23 Сейчас в теме
(29)
добрый день! привык, что вы Цифровой КОТ... в этой статье ни разу не упомянули....
Вопрос такой: а как все эти улучшения ускорили открытие формы в 1 секунду (вместо 5 секунд), и проведение документа в 1 секунду (вместо 10 секунд).


Добрый день! Статья написана по результатам доклада на осенней конференции, а мы тогда планировали делать ребрендинг со сменой названия. В итоге, после получения обратной связи от клиентов и партнеров, решили вернуться к старому названию, так что КоТ по-прежнему в строю.

Ускорение удается получить за счет того, что в интерфейсе нет ничего лишнего, мы не тянем на клиент кучу объектов, не имеющих отношения к решаемой задаче. Если на форме заказа необходимо отобразить только часть реквизитов и ТЧ - мы получаем данные только для них, формируем готовый html и отдаем браузеру. Причем, часть данных (например, табличные части, списки) мы получаем асинхронно после открытия формы и отображения наиболее важной информации. Например, здесь https://digitcat.ru/demo/ipc-itil/ на форме обращения есть дерево подчиненности, которое генерится долго и весит много, мы подгружаем его уже после открытия формы. Количество запросов к серверу увеличивается, но повышается комфорт.

С проведением документов, конечно, такой фокус не пройдет, потому что модуль объекта всегда одинаковый: как в обычном интерфейсе, так и у нас. Но все равно экономим время за счет генерации интерфейса. В наиболее тяжелых случаях используем асинхронную запись: отправляем на сервер данные, возвращаем клиенту ответ и деблокируем интерфейс, на сервере запускаем фоновое задание с проведением документа и дальше все так же, как при выполнении длительных операций в тонком клиенте.

Иногда используем кэширование на клиенте и распределенные конфигурации, об этом написано здесь: https://infostart.ru/1c/articles/883068/, смотрите после заголовка "Интеграция с сайтом как способ увеличения производительности 1С". Например, есть страница со списком товаров, ценами и остатками. Данные об иерархии, наименование товаров, картинки - это условно постоянная информация. Мы выгружаем ее в отдельную базу, которая используется в качестве бэка для портала. За счет того, что в базе нет вообще ничего лишнего, она обеспечивает быстрый возврат данных клиенту. За информацией о ценах и остатках идем в рабочую базу: эти запросы она выполняет быстрее.

И последнее нововведение этого года - реактивные интерфейсы с применением стандартных библиотек типа Vue или React: скорость разработки фронта вырастает в разы, генерация html на сервере 1С не требуется, возвращаем только JSON с данными.
59. comptr 51 17.07.25 20:55 Сейчас в теме
(47)
реактивные интерфейсы с применением стандартных библиотек типа Vue или React: скорость разработки фронта вырастает в разы, генерация html на сервере 1С не требуется, возвращаем только JSON с данными

Т.е. стандартный сайт, только в качестве бэка - 1С с http-сервисами?)
30. coollerinc 198 17.07.25 11:56 Сейчас в теме
Многие накинулись, что надо тестировать без отладки(т.е. ключ debug надо удалить у службы 1с). Но я на практике не встречал, что бы хоть у кого то была выключена отладка.

По поводу сложения строк, скорее надо сравнивать, кода моного слагаемых Текст = Текст1 + "от"+ Текст3 + " " + Текст3. В этом случае СтрШаблон должен быть быстрее. Хотя я не проверял.

Люблю такие статьи, как познавательные. Но ненавижу когда вижу код в одну строку. Так и представляю, какой то новичек прочитал статью и давай херачить простые циклы и условия в одну строку
TitanLuchs; +1 1 Ответить
36. Сисой 88 17.07.25 14:16 Сейчас в теме
(30) Включенная отладка на продакшене? Палкой по голове админу,....
Тестовый контур, на нем -debug
На крупных нагруженных базах разница в производительности весьма заметна
Если конечно, 10 пользователей и одна бухгалтерия - можно и отладку включить
JohnyDeath; dock; +2 1 Ответить
37. coollerinc 198 17.07.25 15:46 Сейчас в теме
(36) Пробовали с отладкой и без отладки работать. То что отладку отключили, пользователи не заметили, УТ11.4 была тогда около 40 одновременных пользователей. А вот то что разбираемся с проблемами дольше чем обычно, они заметили
user597086_dir_box; user2073904; +2 Ответить
52. RocKeR_13 1445 17.07.25 17:35 Сейчас в теме
(36) Тоже у одного клиента (КА, 100+ одновременно работающих пользователей, куча разных интеграций - с сайтом, со складами на аутсорсе, Б24, различные рассылки отчетов, куча триггеров на автоматическое создание документов и еще много всякого интересного) была выключена отладка. В какой-то момент нужно было включить ее на проде, чтобы отловить ошибки: в итоге админ включил, а выключить забыл - так несколько месяцев и работали. В итоге-то выключили, поспрашивали пользователей: они совершенно ничего не заметили)
user597086_dir_box; user2073904; +2 Ответить
77. triviumfan 102 24.07.25 12:10 Сейчас в теме
(52) потому что на глаз её и не увидеть, ведь она около 5-7%.
61. user1832003 59 18.07.25 01:53 Сейчас в теме
(30) много у кого отладка выключена на рабочем сервере. Но это обычно только у тех, у кого большие и загруженные базы. И это реально дает прирост скорости. На маленьких базах все на это забивают
64. coollerinc 198 18.07.25 11:27 Сейчас в теме
(61) У всего есть плюсы и минусы. С включённой отладкой можно быстро понять, в чем причина проблемы. С выключенной, работает быстрее по замерам. Каждый выбирает, то что ему нужно. Я для себя понял, что включенная отладка это большой плюс, когда изменения идут постоянно и на тестировании все косяки просто не отловить.
Вот когда у вас изменения внедряются редко, либо есть штат тестировщиков, то можно отладку отключать
72. gybson 21.07.25 14:15 Сейчас в теме
(30) Претензия не в этом. Просто это один тест, а не 15.
31. booksfill 17.07.25 12:24 Сейчас в теме
По поводу мифа 7 интересно получается.

Даже если убрать лишний TOP 1 и ненужный цикл по Выборка.Следующий(),
все вывести в одну строку.
Да даже параметр запроса установить вне цикла, а в цикле вообще оставить только
"Запрос.Выполнить()";

Все равно запрос серьезно проигрывает методу НайтиПоКоду.

При этом оба подхода генерируют идентичные запросы и планы их выполнения.


sp_executesql можно использовать вместо хранимых процедур для выполнения инструкции Transact-SQL много раз, когда изменение значений параметров в инструкцию является единственным вариантом. Так как сама инструкция Transact-SQL остается константой и изменяется только значения параметров, оптимизатор запросов SQL Server, скорее всего, повторно использует план выполнения, который он создает для первого выполнения.


Cослаться на то, что "ну там же C++" не получается - нет там числодробилок и т.п.

Грешить на "оптимизацию", когда интерпретатор, встретив НайтиПоКоду делает один запрос сразу по списку параметров тоже - профайлер это опровергает.

Объект "Запрос" обращается к процедуре с созданный опцией WITH RECOMPILE?
Нет в обоих случаях это одна и та же процедура, причем служебная.

Получается, что потеря лежит в самом объекте "Запрос", который делает множество вещей никак не связанных с СУБД.
Неясно только каких и, главное, можно ли на это как-то повлиять.

Или собака порылась в чем-то другом?

P.S.
exec sp_executesql N'SEL ECT
T1._IDRRef
FR OM _Reference151 T1 WITH(NOLOCK)
WHERE T1._Code = @P1',N'@P1 nvarchar(4000)',N'ЯРС18368   '
nickperel; user1832003; TitanLuchs; +3 Ответить
32. Viktor_Ermakov 377 17.07.25 12:47 Сейчас в теме
Интересная статья, спасибо. И как оказалась холиварная. Почитаем как будут дальше развиваться замеры)
TitanLuchs; dock; +2 Ответить
35. user916099 17.07.25 14:03 Сейчас в теме
В мифе 15: Представление - это строка неограниченной длины, я думаю, причина замедления выгрузки в таблицу именно в этом.
Если в запросе к представлению применить ВЫРАЗИТЬ(), вероятно, результат измерений качественно изменится.
TitanLuchs; +1 Ответить
48. TitanLuchs 554 17.07.25 17:25 Сейчас в теме
(35) Надо проверить, спасибо!
38. alexer 1028 17.07.25 16:37 Сейчас в теме
Столько лет моей профессиональной деятельности коту под хвост.
Все, пошел переписывать все процедуры и функции в своем коде в одну строку.
maikl007; user2128756; IgorS; Lem0n; +4 Ответить
46. RocKeR_13 1445 17.07.25 17:19 Сейчас в теме
По 10 мифу, кстати, не следует забывать одну важную деталь:

2.2. Следует избегать транзакций, которые выполняются длительное время.

Например, неправильно: для загрузки адресного классификатора записывать все данные, относящиеся к одной версии классификатора в одной транзакции, для того, чтобы в случае ошибки откатить целиком загружаемую версию классификатора. Т.к. данных по одной версии классификатора много (объем около 1 Гб), то для выполнения такой транзакции, во-первых, может не хватить оперативной памяти (особенно при использовании файловой информационной базы на 32-разрядной ОС), а, во-вторых, такая операция будет выполняться достаточно долго и ее нельзя будет оптимизировать за счет выполнения в несколько потоков.

Правильно: разбить загрузку новой версии классификатора на небольшие порции так, чтобы запись порции в одной транзакции не превышала 20 секунд в условиях высоконагруженной информационной системы и реализовать функциональность по откату к предыдущей версии в случае ошибки. Максимальная продолжительность указана исходя из того, что время ожидания установки транзакционной блокировки данных в информационной базе по умолчанию равно 20 сек.
TitanLuchs; +1 Ответить
49. TitanLuchs 554 17.07.25 17:28 Сейчас в теме
(46) Да, я говорил об этом на докладе; подумал, что в статье это вырезали - нет, на месте. Тут немаловажно найти правильный размер обрабатываемой порции.
54. RocKeR_13 1445 17.07.25 17:41 Сейчас в теме
(49) Про "раздавило парней арбузами" - это да, на месте) Но немаловажно, чтобы и по длительности транзакция не растягивалась.
55. TitanLuchs 554 17.07.25 17:44 Сейчас в теме
(54) Я имею в виду последние предложения из мифа 10:

Однако важно помнить: применение транзакции – это тоже лишний алгоритм (аналогично конструктору запроса). Объявление транзакции отнимает время. При слишком малом объеме данных эффект нивелируется, а при чрезмерно большом – получится, что парней раздавило арбузами. Поэтому для каждой задачи необходимо подбирать оптимальный размер порции данных для одной транзакции.

Как раз это имел в виду. Возможно, надо было применить другую формулировку. В любом случае, спасибо за замечание!
RocKeR_13; +1 Ответить
53. TitanLuchs 554 17.07.25 17:39 Сейчас в теме
Коллеги, спасибо всем за оценки и комментарии, все прочитал. На часть ответил адресно, на остальные - ответ в одном общем сообщении, чтобы два раза не вставать.

Про корректность тестирования: файловая/серверная база, включенная отладка. Мы проведем еще один комплексный тест на новом сервере, где все мифы будут проверены:
- на файловой базе и двух клиент-серверных базах: на MSSQL и Postgres
- каждая из трех баз будет развернута в трех экземплярах: минимальный размер, 10-20 гиг, > 200 гиг
- каждый тест будет выполнен при включенной и при отключенной отладке
Итого получится 18 тестов для каждого мифа.
Если считаете, что необходимо добавить что-то еще - предлагайте!

Про то, как выполнялось тестирование:
1. Каждый миф проверялся как на файловой, так и на клиент-серверной базе. Результаты опубликованы для файловой базы.
2. Отладка была включена всегда как на файловой, так и на клиент-серверной базе.
3. Сервер использовался один и тот же.
4. Базы абсолютно одинаковые: вторая создана путем выгрузки первой в dt.
5. Обработка, на которой выполнялось тестирование была встроена в конфигурацию; проверка на внешней обработки выполнялась только для одного мифа.
tolyan_ekb; +1 Ответить
62. user1832003 59 18.07.25 02:08 Сейчас в теме
(53) 8 миф надо переделать.

суть мифа в том, утверждается что

Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить(...);

Пока Выборка.Следующий() Цикл
     ЗаполнитьЗначенияСвойств(Таблица.Добавить(), Выборка);
КонецЦикла;


Работает быстрее чем

Запрос.Выполнить().Выгрузить();


Вопрос лишь в том, делать описание таблицы для заполнения обходом выборки до замера или уже при замере. Можно и так и так проверить.

Кстате тут еще можно и расход памяти замерить.

И еще возможно есть смысл проверить на разном составе колонок

ps в старых темах где-то видел замеры где это подтверждается. В новых платформах замеры показывали уже другое. Была четкая зависимость от количества строк. Чем больше строк в результате запроса - тем быстрее делается именно Запрос.Выполнить().Выгрузить(); чем обход выборки. При этом расход памяти +- одинаковый
87. tormozit 7303 28.07.25 17:57 Сейчас в теме
(62) Запрос.Выполнить().Выгрузить() всегда был и будет быстрее чем создание таблицы плюс заполнение ее из выборки. Преимущество выборки тут только в плавности наполнения таблицы и съедания памяти, т.е. можно остановиться в любой момент например на 100К строк.
88. user1832003 59 29.07.25 02:41 Сейчас в теме
(87) В том то и дело что в последних темках об этом даже расход памяти +- одинаковый

а вот Запрос.Выполнить().Выгрузить() на старых платформах работал медленнее, чем обход выборки если верить замерам с инфостарта. Я лично не проверял, всегда использую выгрузку если нужна таблица целиком
89. tormozit 7303 29.07.25 06:53 Сейчас в теме
(88) Я не писал что расход памяти отличается. Он всегда был и будет одинаковым. Я писал о
плавности съедания памяти
. Запрос.Выполнить().Выгрузить() всегда работал быстрее и это логично, т.к. это одна инструкция встроенного языка вместо Х. Пытаться опровергнуть это можно только качественным тестом.
90. user1832003 59 29.07.25 07:46 Сейчас в теме
(89) я и не опровергаю. Просто где-то видел замеры на старых платформах. На новых все именно так как ты и описываешь
63. Domovoi 4 18.07.25 03:39 Сейчас в теме
7 миф не правильно проверили. НайтиПоКоду и запрос одинаково работают. (Хотя сам всегда считал что запрос быстрее)
Уберите циклы и запустите отдельно найтипокоду, потом перезапустите и отдельно запрос. У вас получается кеширование запроса, передается на найтипокоду.
К примеру если вы без циклов сделаете найтипокоду, а потом запрос в одной процедуре, то найтипокоду проиграет.
78. triviumfan 102 24.07.25 12:32 Сейчас в теме
(63) У меня всегда найтипокоду() быстрее:
Прикрепленные файлы:
80. Domovoi 4 24.07.25 12:37 Сейчас в теме
(78) Так а я о чем написал? У вас запрос закэшировался и найтипокоду просто берет результат из кэша. Местами поменяйте запрос и найтипокоду и будет обратный результат. Их нужно отдельно тестировать с перезапуском сеанса.
81. TitanLuchs 554 24.07.25 12:50 Сейчас в теме
(80) Мы меняли этот код местами, результат был такой же.
82. Domovoi 4 24.07.25 14:11 Сейчас в теме
(81) Прикрепил файл обработки. Под рукой была конфа на ОФ.
При тестировании:
должен быть справочник 100к-1млн записей.
результатом теста не должно быть 0-2млсек, чтоб исключить кэширование. Т.е. если запустить одновременно запрос и найтипокоду, то один должен к примеру за 20 млсек отработать, а второй может за 0-1млсек.
Для норм теста я бы запускал сеанс и выполнял запрос, потом закрывал сеанс, открывал заново и выполнял найти по коду.
Не уверен во внешних обработках и консолях, лучше внедрить обработку в конфу и почистить полный кэш (эта перестраховка скорее от незнания, но так будет чище эксперимент). На УФ лучше не использовать типовую, а сделать каркасную с одним справочником и заполнить его.
Прикрепленные файлы:
ТестМиф7.epf
83. triviumfan 102 24.07.25 14:58 Сейчас в теме
(80) Так достаточно?
Прикрепленные файлы:
84. triviumfan 102 24.07.25 15:08 Сейчас в теме
(80) Или так?
Прикрепленные файлы:
85. Domovoi 4 24.07.25 15:46 Сейчас в теме
(84) нельзя в цикл, там же кэшируется результат после первого прохода.
86. triviumfan 102 24.07.25 16:28 Сейчас в теме
(85) цикл НУЖЕН! Иначе как ты вообще собираешься сравнивать результаты?!
Я просто забыл установить новый код. Вот новые тесты. Неявный запрос всегда быстрей.
Прикрепленные файлы:
66. roman72 402 18.07.25 16:25 Сейчас в теме
Спасибо за статью, очень полезная.
TitanLuchs; +1 Ответить
67. astreikaea 18.07.25 23:14 Сейчас в теме
По поводу Мифа 14. В книге Хрусталевой "Язык запросов" написано, что
"Для ссылочных типов результат функции полностью аналогичен получению поля Представления от ссылки, переданной в качестве параметра функции. Например, ПРЕДСТАВЛЕНИЕ(Товар) в данном случае аналогично Товар.Представление, но первый вариант предпочтительнее." (стр 43).
Где же правда?
user1827801; +1 Ответить
93. AZ_92 30.07.25 14:47 Сейчас в теме
68. Lem0n 435 19.07.25 15:37 Сейчас в теме
про внешние и встроенные обработки есть на ИТС
https://its.1c.ru/db/metod8dev/content/5940/hdoc
69. comol 5375 20.07.25 19:00 Сейчас в теме
Прямо годнота, спасибо. Про "код в одну строку" это прямо... ну вообщем нет слов :)
70. qwinter 684 21.07.25 09:36 Сейчас в теме
(69) "Код в одну строку" это из за отладки. Без нее такого нет.
71. qwinter 684 21.07.25 09:38 Сейчас в теме
Зачем в "Миф 9" СКД получается из макета? Да еще бессмысленное помещение во временное хранилище настроек.
73. brr 184 21.07.25 20:04 Сейчас в теме
Укажите на какой версии платформы выполнялись проверки. На разных версиях результаты могут отличаться.
Есть ещё миф про методы вызываемые из модуля менеджера - методы из ОМ вызываются быстрее.
92. AZ_92 30.07.25 14:46 Сейчас в теме
(73)
Поддерживаю, ощущение, что пост в 2015 году написан.
74. echo77 1927 22.07.25 10:00 Сейчас в теме
(0) В дополнение к Миф 3. Текстовый документ быстрее, чем переменная типа «Строка» сделайте, пожалуйста, проверку на чтение из многострочной строки методом СтрПолучитьСтроку() и ТекстовыйДокумент.ПолучитьСтроку()
76. user1507484 24.07.25 00:21 Сейчас в теме
По мифу 15: в первой его части представление вообще нигде не использовалось и не получалось. Если просто выполнить запрос, его не будет. Оно сформируется либо при выгрузке в таблицу значений, либо при получении выборки и вызове Следующий(). Поэтому, вторая часть этого мифа и выдаёт большую разницу - там уже есть выгрузка, представление действительно формируется.
79. triviumfan 102 24.07.25 12:34 Сейчас в теме
Некоторые "мифы" высосаны из пальца, а некоторые были интересны. Но из-за множества ошибок и сомнительного сценария тестирования плюс не поставил. Жду перетест.
91. AZ_92 30.07.25 14:45 Сейчас в теме
Насчет СУДБ и про скорость файловой базы посмеялся))). Скажу кратко, по СУБД как бы все очевидно, особенно если она на Postge, насчет клиент-серверной, что она может быть медленнее, тут по-моему вопросы к сисадмину и его железу. Как бы клиент-серверная имеет массу преимуществ, начиная от возможности выгрузки базы в любой момент, даже если работают пользователи и заканчивая, что регламентные задания вроде ЭДО уже на новых платформах моуг не запускаться в автоматическом режиме. Вообще про много говорить.
96. kuzyara 2179 04.08.25 09:58 Сейчас в теме
Статья очень холиварная, так как содержит неточности и сравнение тёплого с мягким.

Для более полного раскрытия заблуждения нужна отдельная статья, но за сборку материала +.
Буду рекомендовать использовать этот материал на собесах)
97. DeerCven 41 07.08.25 08:48 Сейчас в теме
Спасибо, полезная статья, по 1 пункту не поверил, но похоже вы правы, протестировал в клиент-серверной базе с/без отладки и всегда циклы в строку в 2-5 раза быстрее выполняются, вот что ответил на это Gemini:
Ключ к пониманию этого феномена лежит в том, как платформа "1С:Предприятие" обрабатывает исходный код. Система 1С является интерпретатором компилируемого типа. Это означает, что перед выполнением исходный код на языке 1С преобразуется во внутренний промежуточный код, так называемый байт-код, который затем исполняется виртуальной машиной 1С.[1]
При компиляции, для обеспечения возможности отладки и корректного отображения номеров строк при возникновении ошибок, в байт-код вставляются специальные операторы. Один из таких операторов, условно называемый LineNum, связывает исполняемый байт-код со строками исходного кода.
Как поясняется в технических статьях, при выполнении многострочного кода виртуальной машине приходится обрабатывать эти LineNum операторы для каждой строки.[1] В то же время, если весь блок кода, например, тело цикла, записан в одну строку, количество таких операторов значительно сокращается. Соответственно, уменьшаются и накладные расходы на их обработку, что и приводит к ускорению выполнения, особенно при большом количестве итераций.

Поэтому все очень даже логично получается
99. tormozit 7303 15.08.25 17:01 Сейчас в теме
98. cdiamond 235 13.08.25 14:44 Сейчас в теме
Не подскажу что именно имелось ввиду в одной бумажке официально полученной, но в ней экспертами утверждалось что более сотни расширений замедляют работу базы, и якобы нужно объединить расширения в более крупные, но общим числом поменьше.
VyacheslavShilov; tormozit; +2 Ответить
Оставьте свое сообщение