Разберем распространенную ситуацию: в файловой базе 1С, к которой пользователи подключаются через локальную сеть по общему сетевому ресурсу, при первом нажатии на кнопку обработки после некоторого периода неактивности система зависает на 5–10 секунд. При повторных нажатиях тот же самый код выполняется мгновенно. Однако стоит сделать паузу в работе — и задержка повторяется снова. Проанализируем, почему возникает такое поведение, как устроена работа файлового движка по сети и как оптимизировать структуру данных и программный код для устранения этих пауз.
Для понимания корня проблемы проанализируем, как платформа 1С работает с файловой базой данных (файлом .1CD) через сетевую папку по протоколу SMB:
.1CD.Посмотрим на исходный запрос, вызывающий задержку:
Функция ОстатокНомНаСкладе(вхНоменклатура)
// Товары в незакрытых сменах
ЗапросКолТовароввСмене = Новый Запрос;
ЗапросКолТовароввСмене.Текст =
"ВЫБРАТЬ
| СУММА(ХранилищеСуточныхПродаж.Количество) КАК СУММАКоличество
|ИЗ
| РегистрСведений.ХранилищеСуточныхПродаж КАК ХранилищеСуточныхПродаж
|ГДЕ
| ХранилищеСуточныхПродаж.СменаЗакрыта = ЛОЖЬ
| И ХранилищеСуточныхПродаж.ЧекФРРаспечатан = ИСТИНА
| И ХранилищеСуточныхПродаж.Номенклатура = &вхНоменклатура";
ЗапросКолТовароввСмене.УстановитьПараметр("вхНоменклатура", вхНоменклатура);
РезЗапросКолТовароввСмене = ЗапросКолТовароввСмене.Выполнить().Выбрать();
Пока РезЗапросКолТовароввСмене.Следующий() Цикл
Если РезЗапросКолТовароввСмене.СУММАКоличество <> Null Тогда
КолТовВСмене = РезЗапросКолТовароввСмене.СУММАКоличество;
Иначе
КолТовВСмене = 0;
КонецЕсли;
КонецЦикла;
// Проверяем остаток
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Склад КАК Склад,
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| &ДатаОст,
| Склад = &выбСписСклады
| И Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("ДатаОст", ТекущаяДата());
Запрос.УстановитьПараметр("выбСписСклады", Объект.Склад);
Запрос.УстановитьПараметр("Номенклатура", вхНоменклатура);
КолОстаток = Запрос.Выполнить().Выбрать();
Если КолОстаток.Количество() = 0 Тогда
Возврат 0;
Иначе
Пока КолОстаток.Следующий() Цикл
Возврат КолОстаток.КоличествоОстаток - КолТовВСмене;
КонецЦикла;
КонецЕсли;
КонецФункции
В данном примере измерение НомерПродажи стоит на первом месте в регистре сведений ХранилищеСуточныхПродаж. Поскольку это поле хранит уникальные ключи, основной индекс формируется по правилу: НомерПродажи + ДатаПродажи + Номенклатура + .... Платформа 1С не может применить индекс, если в условии ГДЕ не используется самое первое поле составного индекса. В результате при каждом первом запуске после сброса кэша вся таблица регистра полностью пересылается по локальной сети.
Главный индекс независимого регистра сведений всегда строится строго по порядку измерений, заданному в дереве конфигурации сверху вниз. Чтобы запрос с отбором по полям СменаЗакрыта, ЧекФРРаспечатан и Номенклатура отрабатывал по индексу без полного сканирования таблицы, выполним следующие шаги:
ХранилищеСуточныхПродаж.СменаЗакрытаЧекФРРаспечатанНоменклатураНомерПродажи (и остальные поля)Упростим и ускорим выполнение кода. Обработку значения NULL при агрегации лучше доверить языку запросов через функцию ЕСТЬNULL, а также исключить лишний цикл выборки для скалярного результата:
Функция ОстатокНомНаСкладеОптимизированная(вхНоменклатура)
// 1. Получаем количество в незакрытых сменах
ЗапросКол = Новый Запрос;
ЗапросКол.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(СУММА(Хранилище.Количество), 0) КАК КоличествоВСмене
|ИЗ
| РегистрСведений.ХранилищеСуточныхПродаж КАК Хранилище
|ГДЕ
| Хранилище.СменаЗакрыта = ЛОЖЬ
| И Хранилище.ЧекФРРаспечатан = ИСТИНА
| И Хранилище.Номенклатура = &Номенклатура";
ЗапросКол.УстановитьПараметр("Номенклатура", вхНоменклатура);
Выборка = ЗапросКол.Выполнить().Выбрать();
КолТовВСмене = 0;
Если Выборка.Следующий() Тогда
КолТовВСмене = Выборка.КоличествоВСмене;
КонецЕсли;
// 2. Получаем остаток по регистру накопления
ЗапросОстатка = Новый Запрос;
ЗапросОстатка.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(ТоварыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| &ДатаОст,
| Склад = &Склад И Номенклатура = &Номенклатура) КАК ТоварыОстатки";
ЗапросОстатка.УстановитьПараметр("ДатаОст", ТекущаяДата());
ЗапросОстатка.УстановитьПараметр("Склад", Объект.Склад);
ЗапросОстатка.УстановитьПараметр("Номенклатура", вхНоменклатура);
ВыборкаОстатка = ЗапросОстатка.Выполнить().Выбрать();
Если ВыборкаОстатка.Следующий() Тогда
Возврат ВыборкаОстатка.КоличествоОстаток - КолТовВСмене;
КонецЕсли;
Возврат -КолТовВСмене;
КонецФункции
Если специфика сети или объем таблицы не позволяют добиться мгновенного отклика через сетевой ресурс Windows, наилучшим архитектурным решением для файловой базы является веб-публикация:
.1CD, установим и настроим веб-сервер (Apache или IIS).http://имя_компьютера/путь_к_базе вместо прямого пути к файлу \\server\base.В чем преимущество: При таком подходе файловый движок 1С выполняется локально на стороне сервера публикации. Запросы обрабатываются на сервере за доли секунды, а клиенту передается только готовая числовая выборка размером в несколько байт, что полностью устраняет проблему сетевых задержек протокола SMB и сброса кэша.
Если задержки после простоя сохраняются, необходимо исключить аппаратное засыпание оборудования:
1Cv8.1CD, а также системные каталоги временных файлов %LOCALAPPDATA%\1C и %APPDATA%\1C в список доверенных исключений сканирования на клиенте и сервере.