Работа с платформой 1С:Предприятие 7.7 в связке с MS SQL Server на базах объемом более 5–10 ГБ часто превращается в испытание для производительности. Штатные механизмы платформы, разработанные десятилетия назад, не всегда способны эффективно использовать ресурсы современного оборудования. В этой статье мы подробно разберем, почему возникают задержки при формировании отчетов и обработок, и как можно ускорить систему в несколько раз, используя как программные, так и административные методы.
Проанализируем ситуацию: автор столкнулся с тем, что база объемом 9 ГБ на мощном сервере (64 ГБ ОЗУ, RAID 10) работает крайне медленно — формирование обработки занимает более 10 минут. Основная причина кроется в архитектуре BkEnd.dll. Эта библиотека выступает посредником между кодом 1С и SQL-сервером. При использовании стандартных методов (например, Запрос или ВыбратьДвижения), 1С транслирует их в T-SQL, часто используя курсоры.
Выясним причину ограничения: в ходе обсуждения было выявлено, что штатный механизм накладывает программное ограничение на количество запросов к SQL-серверу (порядка 1024 запросов в секунду). Это создает «бутылочное горлышко», когда мощный сервер простаивает, а приложение «захлебывается» в мелких транзакциях. Кроме того, 1С 7.7 часто выполняет неявные запросы при обращении к реквизитам через точку, что многократно увеличивает нагрузку на сеть и сервер.
Рассмотрим наиболее эффективный способ оптимизации — использование внешних компонент, таких как 1C++. Это позволяет полностью обойти ограничения BkEnd.dll и отправлять на сервер чистый T-SQL код. Вместо того чтобы заставлять 1С генерировать тысячи мелких запросов, мы пишем один сложный запрос, который выполняется на стороне сервера за доли секунды.
Проанализируем пример того, как меняется подход. Вместо стандартного цикла:
// Стандартный, медленный способ
Процедура Сформировать()
Рег = СоздатьОбъект("Регистр.ОстаткиТоваров");
Рег.ВыбратьИтоги();
Пока Рег.ПолучитьИтог() = 1 Цикл
// Обращение к реквизиту через точку - это лишний запрос к SQL!
ТекТовар = Рег.Товар;
Цена = ТекТовар.БазоваяЦена.Получить(РабочаяДата());
КонецЦикла;
КонецПроцедуры
Мы используем ODBCRecordset. Это позволяет получить все данные (включая цены, остатки и реквизиты справочников) одним пакетом. Посмотрим на логику работы с прямым запросом:
ODBCRecordset.JOIN) для получения данных из связанных таблиц.ТаблицуЗначений.Такой подход снимает проблему «1024 запросов в секунду», так как обращение к серверу происходит один раз для всей выборки.
Если мы работаем с версией SQL 2008 или выше, критически важно правильно настроить сам сервер БД. Разберем ключевые параметры:
Параметр MAXDOP (Maximum Degree of Parallelism): Для 1С 7.7 крайне рекомендуется установить значение 1. Почему это важно? 1С генерирует специфические запросы, которые оптимизатор SQL может попытаться распараллелить. Однако из-за структуры таблиц 7.7 это часто приводит к неоптимальным планам выполнения и взаимным блокировкам (Deadlocks). Установка MAXDOP = 1 заставляет сервер выполнять запрос в одном потоке, что для данной платформы оказывается быстрее и стабильнее.
Shared Memory: Если терминальный сервер (клиенты 1С) и SQL-сервер находятся на одной физической машине, обязательно убедитесь, что используется протокол Shared Memory. Это позволяет данным передаваться через оперативную память, минуя сетевой стек, что значительно снижает задержки (latency).
Рассмотрим правила «гигиены» кода, которые помогут ускорить даже штатные механизмы без использования ВК:
ПолучитьЗначение, Получить (для периодических реквизитов) или создание объектов внутри цикла перебора данных. Старайтесь собрать все нужные параметры заранее.Документ.Контрагент.Город — это отдельный запрос SELECT к базе. Если в списке 1000 строк, вы получите 1000 лишних запросов. Правильнее выгрузить данные в ТаблицуЗначений и работать с ней.ИндексированнаяТаблица.Проанализируем пример оптимизации алгоритма из сообщения 5: «запрос цены в цикле». Рассмотрим, как это исправить:
// Оптимизированный подход
ТЗ_Цены = СоздатьОбъект("ТаблицаЗначений");
// Предварительно заполняем ТЗ_Цены всеми нужными ценами одним запросом
// ...
// В основном цикле ищем цену в ТЗ, а не обращаемся к базе
Пока Выборка.ПолучитьСтроку() = 1 Цикл
Цена = 0;
Если ТЗ_Цены.НайтиЗначение(Выборка.Товар, Стр, "Товар") = 1 Тогда
Цена = ТЗ_Цены.ПолучитьЗначение(Стр, "Цена");
КонецЕсли;
КонецЦикла;
Посмотрим, как можно помочь системе на уровне ОС. 1С 7.7 — это однопоточное приложение. На современных многоядерных процессорах поток может «прыгать» между ядрами. Проанализируем эффект от настройки Affinity Mask: привязка процесса 1cv7s.exe к конкретному ядру процессора (через диспетчер задач или скрипты) позволяет избежать сброса кэша L1/L2 процессора, что дает прирост скорости до 10–15%.
Также обратим внимание на файлы конфигурации. Файлы 1Cv7.md и users.usr постоянно считываются платформой. Для ускорения их чтения рекомендуется:
В 1С 7.7 SQL-версии блокировки часто происходят на уровне всей таблицы. Если отчет формируется долго, он может блокироваться другими пользователями, которые в этот момент записывают документы. Выясним причину через SQL Profiler: если вы видите состояние SUSPENDED и тип ожидания LCK_M_..., значит, ваша обработка просто ждет своей очереди. Решением здесь также станет переход на прямые запросы с использованием конструкции WITH (NOLOCK), которая позволяет читать данные, не обращая внимания на блокировки и не выстраиваясь в очередь.
Подведем итог: Оптимизация 1С 7.7 на SQL — это комплексная задача. Начните с настройки MAXDOP = 1 на SQL-сервере, затем избавьтесь от обращений к базе в циклах. Если это не даст нужного эффекта (в данном случае — сокращение времени с 10 до 1-2 минут), единственным верным путем будет переписывание критических узлов на прямые запросы через 1C++.