При работе с высоконагруженными базами данных 1С, где таблицы итогов регистров накопления (_AccumRgT) разрастаются до сотен миллионов строк, стандартные механизмы платформы начинают работать медленно. Одним из продвинутых способов ускорения является секционирование (partitioning) таблиц на уровне СУБД. Однако многие разработчики сталкиваются с тем, что после настройки секционирования скорость запросов к виртуальным таблицам Остатки не увеличивается. Разберем, почему это происходит и как решить данную проблему.
Рассмотрим ситуацию: вы выполнили секционирование таблицы итогов _AccumRgT по полю _Period (например, по годам). Логично ожидать, что при запросе актуальных остатков (где _Period = '5999-11-01') SQL Server должен мгновенно обращаться только к одной последней секции. Но на практике 1С генерирует запрос через процедуру sp_executesql, передавая дату как параметр.
Проанализируем типичный кусок кода, который ловится в SQL Profiler:
exec sp_executesql N'SELECT ...
FROM dbo._AccumRgT27531 T2 WITH(NOLOCK)
WHERE T2._Period = @P1 ...', N'@P1 datetime2(3)', '5999-11-01 00:00:00'
В этом случае оптимизатор MS SQL Server часто не может заранее определить, в какой секции находятся данные, так как значение @P1 становится известно только в момент выполнения (динамическая фильтрация). Вместо обращения к одной секции, сервер «поднимает» (сканирует) все секции таблицы. Разница в производительности может быть колоссальной: 1 секунда при прямом указании константы против нескольких минут при использовании параметров 1С.
Самый надежный способ заставить СУБД использовать преимущества секционирования — это обойти механизм генерации запросов платформы. Если мы передаем дату как литерал (константу), механизм Partition Elimination (исключение секций) срабатывает безотказно.
Для реализации этого метода можно использовать ADODB.Connection или Внешние источники данных. Выясним, как должен выглядеть запрос, чтобы SQL Server прочитал только нужную секцию:
-- Прямой запрос к таблице итогов
SELECT _Fld1, SUM(_Fld2)
FROM dbo._AccumRgT27531 WITH(NOLOCK)
WHERE _Period = '5999-11-01 00:00:00' -- Указываем дату константой
AND _Fld3RRef IN (SELECT Ссылка FROM #TempTable)
GROUP BY _Fld1
При таком подходе оптимизатор на этапе компиляции плана видит конкретное значение периода и отсекает все ненужные секции за ненадобностью.
Часто проблема медленной работы кроется не только в секциях, но и в «мусоре» внутри таблицы итогов. Выясним важную особенность: платформа 1С при активном использовании Разделения итогов может оставлять миллионы избыточных записей (нулевых или несхлопнутых).
Проанализируем шаги для исправления ситуации стандартными средствами:
УстановитьМинимальныйПериодРассчитанныхИтогов(). Это позволит физически удалить старые итоги (например, за 2010–2015 годы), которые вам уже не нужны в оперативном доступе.Если вы не хотите отказываться от запросов на языке 1С, существует «хитрое» решение на стороне СУБД — использование Plan Guides. Рассмотрим этот механизм: он позволяет принудительно заставить SQL Server использовать определенный план или хинты для конкретного текста запроса.
Вы можете создать структуру, которая будет ловить запрос от 1С и добавлять к нему подсказку OPTION(RECOMPILE). Это заставит SQL Server перекомпилировать план при каждом выполнении с учетом текущих значений параметров (включая дату периода), что позволит активировать исключение секций.
Посмотрим на структуру кластерного индекса таблицы итогов. Обычно он начинается с поля _Period. Если в вашем запросе 1С в условии ГДЕ виртуальной таблицы используется сложный отбор (например, В (ВЫБРАТЬ...) по 50 тысячам строк), оптимизатор может выбрать Index Scan вместо Index Seek.
Рассмотрим, как можно улучшить ситуацию:
Измерение В (ВЫБРАТЬ Ссылка ИЗ ВТ_Отбор), обязательно индексируйте ВТ_Отбор по полю Ссылка. Это поможет SQL Server выбрать Merge Join или Nested Loops.Проанализируем итоговый алгоритм действий для администратора БД и ведущего разработчика:
UPDATE STATISTICS.Важный момент: Помните, что любое прямое вмешательство в структуру таблиц 1С на уровне SQL (включая секционирование) может «слететь» при реструктуризации базы (обновлении конфигурации). Рекомендуется автоматизировать процесс пересоздания секций с помощью DDL-триггеров или скриптов после обновления.