При разработке сложных отчетов в системе 1С:Предприятие, особенно если они предназначены для формирования сводных балансов или анализа больших объемов данных из регистров бухгалтерии, программисты часто сталкиваются с критической ошибкой: «Построенный запрос к СУБД использует слишком много таблиц. Допустимо не более 256». Эта ситуация особенно характерна для систем, работающих под управлением старых версий MS SQL Server (например, 2000 или 2005), где лимит на количество таблиц в одном SELECT является жестким ограничением парсера СУБД.
Рассмотрим подробнее причины возникновения этой проблемы и разберем по шагам проверенные методы ее решения, которые помогут не только устранить ошибку, но и повысить общую производительность системы.
На первый взгляд, запрос в конфигураторе 1С может выглядеть компактно. Однако стоит понимать, как платформа 1С транслирует программный код в SQL-инструкции. Проанализируем основные факторы «размножения» таблиц:
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты — это не запрос к одной физической таблице базы данных. Платформа 1С заменяет это обращение сложным подзапросом, который может объединять таблицу итогов, таблицу движений, таблицы субконто и вспомогательные структуры для расчета развернутого сальдо. Один вызов такой таблицы может «стоить» СУБД от 5 до 15 реальных таблиц.ОБЪЕДИНИТЬ ВСЕ для сбора данных по разным счетам (как в примере автора темы) линейно суммирует количество таблиц. Если у вас 20 блоков ВЫБРАТЬ, каждый из которых обращается к сложной виртуальной таблице, лимит в 256 таблиц будет превышен очень быстро.Счет.Код или Субконто1.Наименование, 1С добавляет к SQL-запросу LEFT JOIN с соответствующей таблицей (справочником или планом счетов).Субконто1) имеет составной тип, включающий 10 справочников, то при попытке получить данные из этого поля без явного указания типа СУБД может попытаться соединить все таблицы этих справочников сразу, чтобы найти нужную ссылку.Самый эффективный способ обойти ограничение СУБД — это разбиение одного огромного запроса на серию последовательных шагов с использованием временных таблиц. С точки зрения SQL-сервера, это будут разные, независимые запросы, для каждого из которых лимит в 256 таблиц будет считаться заново. Рассмотрим, как переработать запрос из сообщения автора.
Вместо одного гигантского ВЫБРАТЬ... ОБЪЕДИНИТЬ ВСЕ..., мы будем помещать результаты каждого промежуточного выбора во временные таблицы. Разберем на примере:
// Первый блок данных помещаем во временную таблицу ВТ_Часть1
ВЫБРАТЬ
1 КАК Раздел1,
1 КАК Раздел2,
1110 КАК Раздел3,
СУММА(ХР.СуммаКонечныйОстаток) КАК Сумма,
ХР.Счет КАК Счет,
ХР.Организация КАК Организация
ПОМЕСТИТЬ ВТ_Данные
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&ДатаНач, &ДатаКон, , , Счет.Код = "04", , ) КАК ХР
СГРУППИРОВАТЬ ПО
ХР.Счет,
ХР.Организация;
////////////////////////////////////////////////////////////////////////////////
// Добавляем следующие данные в ту же временную таблицу через объединение в новом запросе
ВЫБРАТЬ
Раздел1, Раздел2, Раздел3, Сумма, Счет, Организация
ПОМЕСТИТЬ ВТ_Общая
ИЗ
ВТ_Данные КАК ВТ_Данные
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
1, 1, 1110, СУММА(ХР.СуммаКонечныйОстаток), ХР.Счет, ХР.Организация
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&ДатаНач, &ДатаКон, , , Счет.Код = "05", , ) КАК ХР
СГРУППИРОВАТЬ ПО
ХР.Счет,
ХР.Организация;
Проанализируем ситуацию: мы разделили нагрузку. Теперь SQL-сервер сначала выполнит первый запрос и создаст таблицу в tempdb, а затем выполнит второй. Каждый шаг остается в рамках допустимого лимита таблиц.
Важный совет: Если вы работаете в Системе Компоновки Данных (СКД), временные таблицы также прекрасно поддерживаются. Вам нужно лишь описать их последовательно в тексте запроса набора данных, разделяя символом ;.
Второе обязательное правило оптимизации тяжелых запросов — использование функции ВЫРАЗИТЬ для всех полей составного типа. Особенно это касается Субконто в регистрах бухгалтерии.
Рассмотрим пример правильной типизации:
ВЫБРАТЬ
ХР.Счет,
ХР.Организация,
// Вместо просто ХР.Субконто1 используем типизацию:
ВЫРАЗИТЬ(ХР.Субконто1 КАК Справочник.Контрагенты) КАК Контрагент,
СУММА(ХР.СуммаКонечныйРазвернутыйОстатокДт) КАК Дебет
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(...) КАК ХР
ГДЕ
ХР.Счет.Код = "60.01"
Когда мы применяем ВЫРАЗИТЬ, мы явно говорим платформе: «Здесь может быть только этот справочник». В результате 1С не будет подключать лишние таблицы других типов субконто к SQL-запросу, что существенно сократит количество JOIN-ов.
Чтобы ваш запрос работал максимально быстро и стабильно, придерживайтесь следующих правил:
ИНДЕКСИРОВАТЬ ПО после описания временной таблицы.УНИЧТОЖИТЬ. Это освободит место в базе данных tempdb.ОстаткиИОбороты), а не в секцию ГДЕ. Это позволит платформе отобрать данные на более раннем этапе.Таким образом, переход на временные таблицы и явное приведение типов — это не просто способ уйти от технической ошибки MS SQL Server 2005, но и стандарт «хорошего тона» при разработке в 1С. Это делает код более читаемым, а отчеты — быстрыми и надежными в любой среде эксплуатации.