При разработке отчетов или обработок в 1С программисты часто сталкиваются с необходимостью вывести штрихкоды товаров вместе с их остатками и характеристиками. На первый взгляд задача кажется простой, однако при неправильном подходе к проектированию запроса можно столкнуться с критическими ошибками, такими как "Out of memory" в PostgreSQL или крах процесса SQL-сервера. Разберем, почему это происходит и как составить оптимальный запрос.
Проанализируем типичную ситуацию, описанную в сообщениях форума. Когда мы соединяем таблицу остатков с таблицей штрихкодов только по полю Владелец (номенклатура), игнорируя связь по характеристике, возникает эффект «схлопывания» или, наоборот, бесконтрольного размножения строк. Рассмотрим пример: у одной позиции номенклатуры есть 10 характеристик и 5 разных штрихкодов (например, на разные упаковки или типы). Если в условии связи указать только ПО Остатки.Номенклатура = Штрихкоды.Владелец, система для каждой из 10 характеристик выведет все 5 штрихкодов. В итоге вместо 10 строк мы получим 50.
На больших справочниках это приводит к лавинообразному росту объема данных во временных таблицах. База данных пытается обработать миллионы комбинаций, что и вызывает переполнение памяти (Crash/Out of memory).
Вместо того чтобы соединять физические таблицы справочников целиком, мы должны подготовить максимально «легкие» временные таблицы. Первым делом получим только те остатки, которые нам нужны, и только для тех товаров, которые есть на складе. Это отсечет лишние данные в самом начале.
ВЫБРАТЬ
ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
ТоварыНаСкладахОстатки.Характеристика КАК Характеристика,
ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
ПОМЕСТИТЬ ВТОстатки
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК ТоварыНаСкладахОстатки
ИНДЕКСИРОВАТЬ ПО
Номенклатура,
Характеристика
;
Важный момент: обратите внимание на инструкцию ИНДЕКСИРОВАТЬ ПО. Без индексации временных таблиц вложенные циклы при последующих соединениях могут катастрофически замедлить выполнение запроса.
Теперь подготовим таблицу штрихкодов. Важно понимать, что в регистре сведений Штрихкоды поле Характеристика может быть пустым (если учет по характеристикам для данного товара не ведется). Рассмотрим, как правильно подготовить эти данные для связи.
ВЫБРАТЬ
Штрихкоды.Штрихкод КАК Штрихкод,
Штрихкоды.Владелец КАК Владелец,
Штрихкоды.Характеристика КАК Характеристика
ПОМЕСТИТЬ ВТШтрихкоды
ИЗ
РегистрСведений.Штрихкоды КАК Штрихкоды
ГДЕ
Штрихкоды.Владелец В (ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура ИЗ ВТОстатки)
ИНДЕКСИРОВАТЬ ПО
Владелец,
Характеристика
;
Здесь мы применили фильтр ГДЕ Владелец В (...), чтобы не тащить в память штрихкоды всех товаров базы, а ограничиться только теми, что есть на остатке.
Теперь перейдем к финальному объединению. Основная ошибка в сообщении пользователя заключалась в попытке последовательного соединения без учета двойной связи. Нам нужно соединять ВТШтрихкоды одновременно и по номенклатуре, и по характеристике.
Рассмотрим структуру финального запроса:
ВЫБРАТЬ
ВТОстатки.Номенклатура.Код КАК КодНоменклатуры,
ВТОстатки.Номенклатура.Наименование КАК НаименованиеНоменклатуры,
ВТОстатки.Характеристика.Наименование КАК НаименованиеХарактеристики,
ВТШтрихкоды.Штрихкод КАК Штрихкод,
ВТОстатки.КоличествоОстаток КАК Остаток
ИЗ
ВТОстатки КАК ВТОстатки
ЛЕВОЕ СОЕДИНЕНИЕ ВТШтрихкоды КАК ВТШтрихкоды
ПО ВТОстатки.Номенклатура = ВТШтрихкоды.Владелец
И ВТОстатки.Характеристика = ВТШтрихкоды.Характеристика
Проанализируем ситуацию, когда у товара нет характеристики. В 1С в регистрах часто хранится ПустаяСсылка, а не NULL. Если в таблице остатков характеристика заполнена, а в штрихкодах для этой же номенклатуры штрихкод задан только "в целом" (с пустой характеристикой), обычное соединение ПО Характеристика не сработает.
Для решения этой проблемы можно использовать конструкцию ЕСТЬNULL или ВЫБОР, чтобы привести пустые значения к единому виду. Однако наиболее надежным способом в типовых конфигурациях является строгое соответствие: если штрихкод привязан к конкретной характеристике, он должен выводиться только для нее.
Рекомендации для стабильной работы:
ВЫБРАТЬ *. Выбирайте только те поля, которые действительно необходимы для вывода или последующих расчетов.work_mem в конфигурации сервера, однако помните, что оптимизация кода запроса всегда приоритетнее наращивания ресурсов.Таким образом, использование временных таблиц с обязательной индексацией по полям связи и наложение условий соединения одновременно по паре "Номенклатура + Характеристика" позволяет избежать декартова произведения и значительно ускорить работу системы.