Замедление работы 1С:Предприятие часто связано не с аппаратными ограничениями, а с неэффективными запросами к базе данных. Даже на мощном сервере плохо написанный запрос может блокировать таблицы на минуты, вызывая «подвисания» у десятков пользователей. По данным исследований, 80% проблем производительности в 1С решаются оптимизацией именно запросов — без покупки нового «железа».
В этой статье разберём конкретные методы диагностики и ускорения: от анализа планов выполнения до использования виртуальных таблиц и индексов. Особое внимание уделим типичным ошибкам, которые разработчики допускают при работе с Запрос и ОбъектЗапроса, а также нюансам для разных СУБД (MS SQL, PostgreSQL, IBM DB2). Материал будет полезен как администраторам баз данных, так и 1С-программистам, которые хотят писать код, не тормозящий систему.
1. Диагностика «узких мест»: как найти проблемные запросы
Прежде чем оптимизировать, нужно выявить, какие именно запросы тормозят систему. В 1С:Предприятие 8.3 для этого есть встроенные инструменты, но их часто используют неэффективно. Начнём с базовых методов:
- 🔍 Журнал регистрации: включите запись событий с уровнем детализации «
Подробно» (разделАдминистрирование → Журнал регистрации). Ищите запросы с временем выполнения >1 секунды — это потенциальные кандидаты на оптимизацию. - ⏱️ Технологический журнал: если у вас MS SQL, настройте сбор событий
SQL:BatchCompletedиWaitTypesчерез SQL Server Profiler. Для PostgreSQL используйтеpg_stat_statements. - 📊 Монитор производительности 1С: в конфигураторе откройте
Сервис → Монитор производительности. Здесь видно не только время выполнения, но и количество блокировок, которые запрос накладывает на таблицы.
Важно: если в журнале регистрации вы видите запрос с временем выполнения 500 мс, но он выполняется 1000 раз в день — его оптимизация даст больший эффект, чем запроса с временем 5 секунд, но выполняемого раз в неделю. Приоритезируйте по суммарной нагрузке.
Для глубокой диагностики подключитесь напрямую к СУБД. Например, в MS SQL выполните запрос:
SELECT TOP 10
qs.total_elapsed_time/qs.execution_count AS [Avg Duration],
SUBSTRING(qt.text, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(qt.text)
ELSE qs.statement_end_offset END - qs.statement_start_offset)/2)+1) AS [Query Text],
qs.execution_count,
qs.total_logical_reads/qs.execution_count AS [Avg Reads],
qs.total_logical_writes/qs.execution_count AS [Avg Writes]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
ORDER BY [Avg Duration] DESC;
⚠️ Внимание: Если вы используете 1С:Управление торговлей 11.4 или 1С:ERP 2.5, в этих конфигурациях по умолчанию включены дополнительные индексы для аналитических отчётов. Их отключение может ускорить транзакционные операции, но замедлить формирование отчётности. Проверьте нагрузку в пиковые часы (обычно с 9:00 до 11:00).
2. Оптимизация структуры запроса: от WHERE до JOIN
Самая распространённая ошибка — избыточные соединения таблиц (JOIN). Многие разработчики добавляют LEFT JOIN «на всякий случай», не понимая, как это влияет на план выполнения. Правила оптимизации:
- 🚫 Избегайте
SELECT: всегда указывайте только нужные поля. Например, вместоВЫБРАТЬ ИЗ Документ.ЗаказПокупателяпишитеВЫБРАТЬ Дата, Номер, СуммаДокумента. - 🔄 Заменяйте
LEFT JOINнаINNER JOIN, если вам не нужны записи без связей. Это сокращает объём обрабатываемых данных. - 📌 Переносите фильтры в
WHERE: условия по связанным таблицам лучше указывать прямо в основном запросе, а не в подзапросах. - 🗑️ Удаляйте неиспользуемые подзапросы: часто в коде остаются фрагменты вида
ГДЕ Сумма(ВЫБРАТЬ 1 ИЗ Таблица ГДЕ ...) > 0, которые можно заменить наСУЩЕСТВУЕТ.
Пример плохого запроса (типичная ошибка новичков):
ВЫБРАТЬ
Заказы.Номер КАК НомерЗаказа,
Клиенты.Наименование КАК Клиент,
Товары.Наименование КАК Товар
ИЗ
Документ.ЗаказПокупателя КАК Заказы
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Клиенты
ПО Заказы.Контрагент = Клиенты.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя.Товары КАК ТоварыЗаказа
ПО ТоварыЗаказа.Ссылка = Заказы.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Товары
ПО ТоварыЗаказа.Номенклатура = Товары.Ссылка
ГДЕ
Заказы.Дата МЕЖДУ &НачалоПериода И &КонецПериода
После оптимизации:
ВЫБРАТЬ
Заказы.Номер КАК НомерЗаказа,
Клиенты.Наименование КАК Клиент,
Товары.Наименование КАК Товар
ИЗ
Документ.ЗаказПокупателя КАК Заказы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Клиенты
ПО Заказы.Контрагент = Клиенты.Ссылка
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ЗаказПокупателя.Товары КАК ТоварыЗаказа
ПО ТоварыЗаказа.Ссылка = Заказы.Ссылка
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Товары
ПО ТоварыЗаказа.Номенклатура = Товары.Ссылка
ГДЕ
Заказы.Дата МЕЖДУ &НачалоПериода И &КонецПериода
И НЕ Заказы.ПометкаУдаления
Замена LEFT JOIN на INNER JOIN может ускорить запрос в 2–3 раза, если вам не нужны записи без связей.
3. Индексы: как заставить СУБД работать быстрее
Индексы — это ключ к ускорению запросов, но их неправильное использование может, наоборот, замедлить систему. Основные правила:
- 🎯 Создавайте индексы для полей в
WHERE,JOINиORDER BY. Например, если вы часто фильтруете заказы по дате, добавьте индекс на полеДата. - 🔄 Обновляйте статистику индексов: в MS SQL выполните
EXEC sp_updatestats, в PostgreSQL —ANALYZE. - 🚫 Не индексируйте поля с низкой селективностью (например,
ПометкаУдаленияилиЭтоГруппа). Индекс по такому полю не ускорит поиск. - 📊 Используйте составные индексы для часто используемых комбинаций полей. Например, если вы всегда фильтруете по
ДатаиКонтрагент, создайте индекс(Дата, Контрагент).
В 1С:Предприятие индексы можно создавать:
- Через конфигуратор: откройте свойства таблицы (например,
Документ.ЗаказПокупателя) и на закладкеИндексыдобавьте нужные поля. - Через SQL: для MS SQL выполните:
CREATE INDEX IX_Заказы_Дата ON dbo._Document123 (Дата)(где
123— числовой идентификатор документа в метаданных).
| Тип индекса | Когда использовать | Пример для 1С |
|---|---|---|
| Кластерный | Для первичных ключей (автоматически создаётся 1С) | _IDRRef в таблицах документов |
| Некластерный | Для часто фильтруемых полей | Индекс по полю Номер в справочнике Контрагенты |
| Составной | Для комбинаций полей в WHERE |
(Дата, Контрагент, Склад) для отчётов по продажам |
| Покрывающий | Когда индекс содержит все нужные поля запроса | Индекс (Дата, СуммаДокумента) для запроса ВЫБРАТЬ Дата, СуммаДокумента |
⚠️ Внимание: В 1С:Бухгалтерии 3.0 при обновлении на версии старше 3.0.125 автоматически создаются индексы для регистров бухгалтерии. Их ручное удаление может привести к ошибкам при проведении документов. Перед изменением индексов сделайте резервную копию и проверьте в тестовой базе.
4. Виртуальные таблицы: скрытый инструмент ускорения
Виртуальные таблицы — это специальные представления данных, которые 1С формирует «на лету». Они позволяют получать агрегированные данные (например, остатки или обороты) без ручного написания сложных запросов. Их использование может уменьшить нагрузку на СУБД в 5–10 раз.
Основные виды виртуальных таблиц:
- 📈 Остатки:
РегистрНакопления.ТоварыНаСкладах.Остатки()— возвращает остатки на указанную дату. - 🔄 Обороты:
РегистрНакопления.Продажи.Обороты()— суммы операций за период. - 📊 ОстаткиИОбороты: комбинированный вариант для отчётов.
- 🗂️ СрезПоследних:
РегистрСведений.ЦеныНоменклатуры.СрезПоследних()— актуальные данные на дату.
Пример использования виртуальной таблицы вместо ручного запроса:
Плохо (ручной запрос с группировкой):
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Товар,
СУММА(ТоварыНаСкладах.Количество) КАК Остаток
ИЗ
Документ.ОприходованиеТоваров.Товары КАК ТоварыНаСкладах
ГДЕ
ТоварыНаСкладах.Документ.Дата <= &ТекущаяДата
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Номенклатура
Хорошо (виртуальная таблица):
ВЫБРАТЬ
ОстаткиТоваров.Номенклатура КАК Товар,
ОстаткиТоваров.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&ТекущаяДата, ) КАК ОстаткиТоваров
Преимущества виртуальных таблиц:
- ⚡ Готовая оптимизация: 1С сама выбирает самый эффективный план выполнения.
- 📉 Меньше нагрузки на СУБД: не нужно группировать данные вручную.
- 🔄 Автоматическое обновление: при изменении данных в регистре виртуальная таблица всегда актуальна.
Когда НЕ стоит использовать виртуальные таблицы?
Если вам нужны данные с дополнительными фильтрами, которые не поддерживаются виртуальной таблицей (например, связь с другими справочниками через LEFT JOIN). В этом случае ручной запрос может быть гибче.
5. Планы выполнения: как их читать и исправлять
План выполнения запроса — это «карта», по которой СУБД ищет данные. Если план неоптимален, даже простой запрос может работать медленно. В 1С:Предприятие план можно получить так:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Номер КАК НомерЗаказа
|ИЗ
| Документ.ЗаказПокупателя КАК Заказы
|ГДЕ
| Заказы.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
План = Запросы.ПолучитьПланВыполнения(Запрос);
Что искать в плане:
- 🔍
Table ScanилиClustered Index Scan: означает, что СУБД сканирует всю таблицу. Решение — добавить индекс. - 🔄
Hash MatchилиNested Loops: сложные соединения. Попробуйте упростить запрос или добавить индексы. - 📊
Sortв середине плана: сортировка больших объёмов данных. ПеренеситеORDER BYв подзапрос или добавьте индекс. - ⚠️
SpoolилиLazy Spool: временные таблицы. Это признак неэффективного плана.
Пример плохого плана (из MS SQL):
Если вы видите:
|--Clustered Index Scan(OBJECT:([dbo].[_Document123] AS [Заказы]))
|--Hash Match(Inner Join, HASH:([Клиенты].[Ссылка])=([Заказы].[Контрагент]))
|--Clustered Index Scan(OBJECT:([dbo].[_Reference14] AS [Клиенты]))
Это значит, что:
- СУБД сканирует всю таблицу заказов (
Clustered Index Scan). - Использует дорогое соединение
Hash Match.
Решение: добавьте индексы на поля Дата и Контрагент в таблице заказов.
☑️ Проверка плана выполнения
6. Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки, которые тормозят систему. Вот самые распространённые:
- 🔄 Подзапросы в
WHERE:Плохо:
ГДЕ Сумма(ВЫБРАТЬ 1 ИЗ Документ.ЗаказПокупателя ГДЕ Контрагент = &Контрагент) > 0Хорошо:
ГДЕ СУЩЕСТВУЕТ (ВЫБРАТЬ 1 ИЗ Документ.ЗаказПокупателя ГДЕ Контрагент = &Контрагент) - 📊 Функции над полями в
WHERE:Плохо:
ГДЕ ЛЕВ(Заказы.Номер, 3) = "АБВ"(индекс не используется)Хорошо:
ГДЕ Заказы.Номер LIKE "АБВ%" - 🗑️ Избыточные данные в
SELECT:Плохо:
ВЫБРАТЬ Заказы.*(выбираются все поля, включая ненужные)Хорошо:
ВЫБРАТЬ Заказы.Номер, Заказы.Дата, Заказы.СуммаДокумента - ⏱️ Отсутствие ограничений по дате:
Плохо:
ВЫБРАТЬ * ИЗ Документ.ЗаказПокупателя(сканирует всю таблицу)Хорошо:
ВЫБРАТЬ * ИЗ Документ.ЗаказПокупателя ГДЕ Дата >= ДобавитьМесяц(ТекущаяДата(), -1)
Ещё одна частая проблема — блокировки. Если запрос долго держит блокировки, другие пользователи не могут работать с данными. Чтобы уменьшить блокировки:
- 🔒 Используйте
ДЛЯ ИЗМЕНЕНИЯтолько там, где действительно нужно изменять данные. - 📌 Разбивайте большие транзакции на более мелкие.
- ⚡ Уменьшайте время выполнения запроса (см. предыдущие разделы).
⚠️ Внимание: В 1С:Зарплата и управление персоналом 3.1 при расчёте зарплаты за месяц часто возникают блокировки на регистре РасчетыСотрудников. Если расчёт «зависает», проверьте, не держит ли кто-то транзакцию открытой (например, не закрыто окно документа).
7. Оптимизация для конкретных СУБД: MS SQL vs PostgreSQL
Разные СУБД по-разному оптимизируют запросы. Что работает в MS SQL, может быть неэффективно в PostgreSQL, и наоборот.
| Параметр | MS SQL Server | PostgreSQL |
|---|---|---|
| Индексы | Поддерживает включённые столбцы (INCLUDE) |
Нет включённых столбцов, но есть частичные индексы (WHERE в определении) |
| Планы выполнения | Использует SET SHOWPLAN_TEXT ON |
Использует EXPLAIN ANALYZE |
| Ограничение выборки | TOP 100 или FETCH FIRST 100 ROWS ONLY |
LIMIT 100 |
| Работа с датами | Функции DATEADD, DATEDIFF |
Операторы + interval, DATE_PART |
| Транзакции | Поддерживает READ COMMITTED SNAPSHOT |
Использует MVCC (Multi-Version Concurrency Control) |
Примеры оптимизации для разных СУБД:
Для MS SQL:
- 📌 Используйте
WITH (NOLOCK)для запросов, где не важна 100% актуальность данных (например, отчёты):
ВЫБРАТЬ
Заказы.Номер КАК НомерЗаказа
ИЗ
Документ.ЗаказПокупателя КАК Заказы WITH (NOLOCK)
ГДЕ
Заказы.Дата = &ТекущаяДата
Для PostgreSQL:
- 📊 Используйте
EXPLAIN ANALYZEдля детального анализа:
EXPLAIN ANALYZE
SELECT "Номер" AS "НомерЗаказа"
FROM "_Document123" AS "Заказы"
WHERE "Дата" = '2023-10-01';
В PostgreSQL также полезно настраивать параметры work_mem и shared_buffers в postgresql.conf, если у вас много сложных запросов с сортировкой.
В PostgreSQL для ускорения запросов с LIKE используйте расширение pg_trgm. Оно позволяет создавать индексы для поиска по части строки (например, WHERE Наименование LIKE '%текст%').
8. Автоматизация оптимизации: инструменты и скрипты
Ручная оптимизация каждого запроса — долгий процесс. К счастью, есть инструменты, которые помогут автоматизировать часть работы:
- 🔧 1С:Анализ производительности: встроенный инструмент в конфигураторе (
Сервис → Анализ производительности). Показывает «тяжёлые» запросы и предлагает варианты оптимизации. - 📊 SQL Diagnostic Manager (для MS SQL): мониторит производительность в реальном времени и предлагает улучшения.
- 🤖 Скрипты для автоматического создания индексов:
Пример для MS SQL (ищет отсутствующие индексы):
(migs.user_seeks + migs.user_scans) AS [IndexAdvantage],SELECTmigs.avg_total_user_cost (migs.avg_user_impact / 100.0)
'CREATE INDEX [IX_' + OBJECT_NAME(migs.object_id) + '_' +
REPLACE(REPLACE(REPLACE(ISNULL(mid.equality_columns, ''), ', ', '_'), '[', ''), ']', '') +
CASE WHEN migs.group_handle > 0 THEN '_' + CAST(migs.group_handle AS VARCHAR) ELSE '' END +
'] ON ' + migs.statement +
' (' + ISNULL(mid.equality_columns, '') +
CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN ',' ELSE '' END +
ISNULL(mid.inequality_columns, '') + ')' +
ISNULL(' INCLUDE (' + mid.included_columns + ')', '') AS [CreateIndexStatement],
migs.*
FROM
sys.dm_db_missing_index_groups mig
INNER JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
WHERE
migs.avg_total_user_cost (migs.avg_user_impact / 100.0) (migs.user_seeks + migs.user_scans) > 1000
ORDER BY
[IndexAdvantage] DESC;
- 🔄 1С:Центр управления производительностью: отдельный продукт для мониторинга и оптимизации кластеров 1С.
Для автоматизации также можно использовать регламентные задания в 1С, которые будут:
- Еженедельно обновлять статистику индексов.
- Ежедневно чистить журнал регистрации (если он разросся до гигабайтов).
- Ежемесячно проверять фрагментацию индексов (для MS SQL).
Автоматические инструменты не заменяют ручную оптимизацию, но помогают находить проблемы, которые сложно заметить вручную (например, медленное накопление блокировок в фоне).
Не забывайте про тестирование: перед применением изменений на рабочей базе проверяйте их в тестовом контуре. Особенно это касается:
- Создания/удаления индексов.
- Изменения структуры таблиц.
- Обновления конфигурации.
⚠️ Внимание: В 1С:Комплексная автоматизация 2.4 при обновлении на версии старше 2.4.10 автоматически включается механизмУправляемые блокировки. Он может конфликтовать с ручными блокировками в запросах. Если после обновления появились «зависания», проверьте настройки блокировок вАдминистрирование → Настройки программы → Производительность.
FAQ: Частые вопросы по оптимизации запросов в 1С
❓ Как узнать, какой именно запрос тормозит систему?
Используйте технологический журнал (для 1С) или SQL Profiler (для MS SQL). Включите запись событий с фильтром по времени выполнения (>1000 мс). Также поможет встроенный Монитор производительности в конфигураторе.
❓ Почему запрос работает быстро в тестовой базе, но медленно на рабочей?
Причины могут быть разные:
- 📊 Объём данных: в рабочей базе больше записей, и план выполнения меняется.
- 🔄 Блокировки: другие пользователи могут блокировать таблицы.
- 🗑️ Фрагментация индексов: