При выполнении длительных групповых обработок в 1С:Предприятии 7.7 (например, при архивации периода, пометке на удаление большого массива документов или проведении операций) на SQL-версии разработчики и администраторы часто сталкиваются с критической ошибкой: SQL State: HYT00 Native: 0 Message: [Microsoft][ODBC SQL Server Driver]Query timeout expired.
Разберем детально, почему возникает данное сообщение, в чем заключается распространенное заблуждение при попытке его исправить и какие методы решения позволяют гарантированно обойти это ограничение.
Проанализируем механику работы платформы 1С 7.7 с базами данных SQL Server. В штатном движке 1С 7.7 используется ODBC-драйвер, в котором установлено жесткое ограничение на время выполнения одного одиночного SQL-запроса — 30 секунд. Если любой запрос, сформированный платформой, выполняется на стороне СУБД дольше этого времени, транзакция прерывается и SQL Server возвращает таймаут.
Часто разработчики пытаются решить проблему объединением всех шагов обработки в одну большую транзакцию и изменением параметров среды SQL Server Management Studio (SSMS), например, через Tools -> Options -> Designers -> Transactions time-out after. Важно понимать, что этот параметр влияет исключительно на внутренние визуальные дизайнеры SSMS и никак не распространяется на внешние ODBC-соединения, создаваемые платформой 1С 7.7.
Когда все действия выполняются в рамках единой транзакции, возникают дополнительные факторы, замедляющие работу:
.ldf) начинают стремительно расти. На время выделения нового дискового пространства SQL Server приостанавливает выполнение запроса. Для журнала транзакций не работает быстрая инициализация, поэтому заполнение пространства нулями занимает много времени и выбивается из 30-секундного лимита.Самым правильным архитектурным решением в 1С 7.7 является разбиение общего объема работы на небольшие порции (отдельные транзакции по 500–2000 документов). Это не дает одиночному SQL-запросу выходить за пределы 30 секунд.
Чтобы исключить потерю данных в случае сбоя без использования единой транзакции, разберем алгоритм с логированием статуса выполнения:
Рассмотрим пример организации порционной обработки в коде 1С 7.7:
ВыбратьДокументы();
Счетчик = 0;
НачатьТранзакцию();
Пока ПолучитьДокумент() = 1 Цикл
// Выполняем необходимые действия над документом
Док = ТекущийДокумент();
Док.Удалить(0); // Пометка на удаление
Счетчик = Счетчик + 1;
// Фиксируем транзакцию каждые 500 документов
Если Счетчик % 500 = 0 Тогда
ЗафиксироватьТранзакцию();
ОбработкаПрерыванияПолученияСобытий();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
// Завершаем оставшуюся транзакцию
Если Счетчик % 500 <> 0 Тогда
ЗафиксироватьТранзакцию();
Иначе
ОтменитьТранзакцию();
КонецЕсли;
Перед запуском тяжелых регламентных или архивных процедур необходимо выполнить базовую подготовку СУБД:
.ldf) с запасом до начала обработки. Задайте фиксированный шаг авторасширения в мегабайтах (например, по 512 МБ), а не в процентах.Perform volume maintenance tasks («Выполнение задач по обслуживанию тома»). Это исключит задержки при заполнении нулями файла данных (.mdf).UPDATE STATISTICS и перестройте индексы (ALTER INDEX REBUILD) для основных таблиц конфигурации.Если требуется выполнить массовое изменение или удаление данных без возможности разбиения на короткие транзакции в 1С, рассмотрим вариант с использованием объекта ADODB.Command. В ADODB существует возможность явно задать свойство CommandTimeout = 0, что снимает любые ограничения по времени выполнения запроса.
Посмотрим на пример выполнения прямого T-SQL запроса из 1С 7.7:
Connection = СоздатьОбъект("ADODB.Connection");
Connection.ConnectionString = "Driver={SQL Server};Server=ИмяСервера;Database=ИмяБазы;Trusted_Connection=Yes;";
Connection.Open();
Command = СоздатьОбъект("ADODB.Command");
Command.ActiveConnection = Connection;
// Отключаем ограничение по времени выполнения
Command.CommandTimeout = 0;
// Пример прямого T-SQL запроса на пометку удалена
Command.CommandText = "UPDATE _1SOPER SET ISMARK = 1 WHERE DATE < '20170101'";
Command.Execute();
Connection.Close();
Выяснив причины ошибки Query timeout expired, мы видим, что главная задача заключается в том, чтобы не допускать выполнения тяжелых одиночных SQL-запросов дольше 30 секунд. Использование пакетной обработки и предварительная подготовка файлов базы данных позволяют успешно проводить любые длительные регламентные операции в 1С 7.7.