Ошибки при написании запросов, которые допускают все (делаем свой чек-лист)

28.10.25

Разработка - Запросы

Ошибки в запросах совершают все – даже самые опытные разработчики. На реальных примерах из код-ревью показываем, какие промахи незаметно закладывают мины замедленного действия в коде и работе базы. Статья поможет взглянуть на привычные запросы под другим углом и составить собственный чек-лист для уверенной и чистой разработки.

Я занимаюсь разработкой и довольно часто провожу ревью кода – практически каждый день. Одна из моих любимых тем в разработке – это запросы. Интерес к ним у меня появился еще во времена «семерки». Если кто-то помнит, там были прямые запросы в SQL, и возможностей было заметно больше.

 

 

С помощью запросов можно реализовать многие вещи, которые стандартными средствами 1С недоступны.

Представьте, что мы идем в магазин. Чтобы ничего не забыть, мы составляем список покупок. В магазине мы сверяемся с ним: смотрим, что уже в корзине, и что еще нужно взять. Когда все куплено – отлично, задача выполнена.

В разработке все устроено аналогично. У нас есть чек-лист – список, в котором мы фиксируем, что именно нужно сделать и что проверить. Сравниваем план с результатом, убеждаемся, что все выполнено – и можем двигаться дальше.

 

Единообразие кода и команда разработчиков

 

Есть хорошая фраза: «все должно быть безобразно-единообразно». Кажется, ее говорил наш техлид в тот момент, когда речь шла о важности унификации кода в компании.

У нас достаточно большой пул разработчиков 1С – целый центр компетенции. Но даже в небольшой команде, где работает всего четыре с половиной разработчика, часто проявляется принцип «каждый сам себе художник». Каждый пишет код так, как он видит. Чтобы внести порядок и согласованность, мы придерживаемся упомянутого принципа единообразия.

Конечно, не все можно автоматизировать. В запросах часть проверок можно возложить на инструменты автоматического анализа. Но, например, таких моментов, которые Sonar регулярно находит – соединение с виртуальной таблицей без параметров отбора или забытые условия в запросе, – в моей статье не будет.

 

Психология и очевидные вещи

 

Небольшое лирическое отступление. В нашей компании много внимания уделяется заботе о сотрудниках: регулярно проводятся вебинары с психологами. И примерно месяц назад на одном из таких мероприятий мне запомнилась интересная мысль. Психолога часто спрашивали о каких-то «сакральных» практиках: что нужно сделать особенного, чтобы все получилось. А он в ответ уточнял: «А вы делаете самые очевидные вещи?»

«Ну, это же понятно», – отвечали ему. На что он замечал: «Если вы не делаете очевидное, то никакие особенные методы не помогут».

Чек-лист как раз и является такой «очевидной вещью». Он помогает не забывать про простые, но важные шаги и двигаться вперед.Хотя бы для того, чтобы понимать, как правильно, очень полезно обращаться к чек-листу.

Конечно, никто не идеален. Иногда приходится делать что-то неправильно, потому что сроки поджимают. Но даже в таком случае важно помнить: да, я сейчас делаю неправильно, но я делаю это сознательно, понимая последствия.

 

История создания чек-листа

 

 

В 2021 году, когда я проработал в компании всего несколько месяцев, у нас была небольшая команда: три разработчика и куратор. Куратор регулярно проводил ревью нашего кода и в какой-то момент заметил, что ошибки начинают повторяться.

Я был, наверное, главным генератором этих повторяющихся ошибок. Мы поговорили лично, и я пообещал больше так не делать, а заодно выписать для себя список наиболее частых промахов. Но руки у меня так и не дошли, а куратор сделал для нас общий чек-лист. В основном он был посвящен объектной модели.

 

 

Выглядел он примерно так: страничка убористого текста в Confluence, которая висела на виду для всех.

С тех пор все команды компании, которые работают с 1С, стараются этого чек-листа придерживаться. Часть пунктов там вполне очевидна: например, не дублировать код, не писать запросы в цикле, делать нулевое тестирование перед тем, как передать задачу на проверку.

Когда я стал проводить ревью на базе большого чек-листа по объектной модели, я заметил, что в запросах тоже начинают повторяться одни и те же ошибки. Так появилась идея создать свой отдельный подраздел.

У нашей команды есть собственная страничка на портале Confluence: там размещен тот самый большой чек-лист по объектной модели, а под ним мы добавили наш чек-лист по языку запросов.

 

 

Первые пункты в нем появились примерно в мае: их было всего 4–5. А через пару месяцев список вырос уже до десяти. Ко второму пункту сразу сделали картинку, потому что у ребят возникали вопросы. Так удобнее: сразу видно, о чем идет речь, и не нужно гадать.

 

Категории ошибок

 

Общая идея моей статьи – показать, как мы организовали работу у себя и как, возможно, это сможете сделать и вы.

Выше были показаны ошибки в том виде, как они появлялись и как мы их фиксировали. Долгое время они просто выписывались в список и оставались там без особой структуры. Но для статьи я решил систематизировать материал.

В итоге список я разделил на несколько категорий:

  • «Оформление» или «чистота кода».

  • Ошибки в логике. Дальше будут примеры, и станет понятнее, почему я их так назвал (возможно, кто-то сделает для себя другую классификацию).

  • Раздел про элементы оптимизации.

  • Раздел, который я обозначил как «неоднозначность интерпретации». Раньше это называлось «упрощение интерпретации», но мне подсказали, что это не совсем верно: упрощение – это скорее результат исправления ошибок. А вот сами ошибки, которые ведут к неоднозначному пониманию кода, я и выделил в категорию «неоднозначность».

 

Пример 1: Неиспользуемые поля

 

 

Первый пример – неиспользуемые поля.

Когда мы делаем выборку из таблиц, часто бывает так: разработчик двойным кликом берет всю таблицу в конструкторе, и весь состав полей автоматически попадает в выборку. Потом часть этих полей убирается, часть остается, но до конца список никто не проверяет. В результате остаются поля, которые фактически не используются.

Чаще всего такие поля «висят» после того, как запрос уже устоялся, и в него начинают вносить изменения. В процессе доработок про ненужные поля просто забывают.

Да, это не критичная ошибка. Она в первую очередь засоряет код и усложняет его восприятие. Но если говорить об оптимизации, то ситуация меняется: одно лишнее поле или несколько «забытых» полей в выборке по очень большой таблице могут заметно повлиять на производительность.

 

Пример 2: Неиспользование представления

 

 

 

Следующий пример ошибки – неиспользование представления.

В языке запросов есть Представление и ПредставлениеСсылки. Очень часто возникает задача: из финальной выборки нужно взять поля и, например, вывести сообщение пользователю.

Для этого совсем не обязательно тащить саму ссылку. Мы можем прямо в запросе обернуть ее в представление и использовать именно его в объектной модели.

 

Пример 3: Таблицы без выборки полей

 

 

Еще один пример – таблицы без выборки полей.

Здесь важно быть внимательнее с условиями. Когда у нас идет соединение таблиц и из них не выбираются поля, ситуация может быть разной. Если это внутреннее соединение – оно накладывает условия и влияет на результирующую выборку. А вот если соединение левое и при этом поля из присоединенной таблицы не выбираются, интерпретатор просто игнорирует такое соединение.

Формально это не ошибка, скорее вопрос оформления: так код становится менее чистым и менее понятным. Но такие случаи бывают, поэтому я и отметил для себя – нужно быть аккуратнее.

Иногда встречается и более тонкий момент: внизу запроса могут дописать условие – например, сравнение поля основной таблицы с полем левой таблицы. Тут важно быть особенно внимательным, чтобы не получить неожиданный результат.

Пример 4: ЕСТЬNULL для поля основной таблицы

 

 

Вот один из примеров, который, как мне кажется, когда-то ловил Sonar.

Некоторые правила мы в команде отключили по договоренности. Сейчас найти все отключенные правила практически невозможно – их, наверное, больше 500. Так что точных данных нет.

В примере поле берется из основной таблицы, и NULL-значений быть не должно. Сбивает с толку при чтении запроса.

 

Пример 5: Разыменование и соединения

 

 

Возможно, что для подобных случаев существовало одно из правил Sonar (точно не помню).

Здесь разыменование, и общее правило: когда больше одной точки, нужно обернуть в ЕСТЬNULL, указать значение подмены, и все будет хорошо. И не забывать, что разыменование – это, по сути, неявное соединение.

 

Пример 6: Декартово произведение

 

 

Интересный случай, на который стоит обратить внимание.

Добавляется поле в одну таблицу и в другую таблицу, оно заполняется одинаковым значением, чтобы потом сделать соединение. В данном случае это приводит к так называемому декартову произведению. Немногие хорошо знакомы с этим понятием.

Здесь важно то, что в нашем чек-листе есть соответствующая строка. Когда приходит новый разработчик и видит незнакомое понятие, он начинает гуглить, получает информацию – и этот опыт у него откладывается, что помогает избежать ошибок в будущем.

 

 

Другой пример – в отличии от декартова, это «сложение» таблиц (а не произведение), важно не путать, т.к. в одном случае при отсутствии записей в одной из таблиц в итоге будет пустая выборка, а в другом нет.

 

Ошибки логики

 

Пример 7: Использование ЕСТЬNULL для выражения, а не для поля

 

 

Теперь переходим к разделу «ошибки логики».

Основной пример здесь связан с использованием ЕСТЬNULL. Проблема возникает, когда в ЕСТЬNULL прячется выражение, составные части которого сами по себе могут принимать значение NULL.

Внизу показан правильный вариант: мы каждое такое выражение оборачиваем в оператор подмены NULL-значений, а затем собираем в общее выражение. Это может быть произведение, сумма, оператор выбора – вариантов много. Главное – контролировать каждое отдельное значение, чтобы избежать неожиданных результатов из-за NULL.

 

Пример 8: Протягивание поля через запрос

 

 

Ии… постепенно переходим к теме оптимизации.

Пример из реальной практики – «протягивание» поля через половину запроса. По сути, условие следовало бы сразу поместить в параметры виртуальной таблицы, но вместо этого оно «протаскивается» через весь запрос. В нашем случае это был пакет из девяти запросов между первым и последним. Только в самом конце выполняется отбор, хотя его можно было бы сделать сразу в начале.

У меня в конце будут две ссылки на статьи, которые меня вдохновили. Одна из них – статья Артема Кузнецова. Он как раз обсуждает похожую идею: не нужно «тащить» ссылку через весь запрос. Вместо этого лучше получить значения по ссылке в результирующей выборке. То есть через запрос мы пробрасываем ссылку, а конкретные значения получаем только там, где они реально нужны.

 

Пример 9: Лишние временные таблицы

 

 

Лишние временные таблицы – это именно тот пример, который отражен на изображении в чек-листе по запросам.

Вопросы по нему возникли не случайно: что за «лишние» временные таблицы? Я называю это «размазыванием тонким слоем по тарелочке». Переносимся в то время, когда разработчикам платили за количество строк кода.

Вместо того чтобы сделать сразу два левых соединения, почему-то создаются две временные таблицы. *Вендор утверждает, что 6–7 левых соединений – это нормально, но, если их больше, запрос лучше разбивать.

 

Пример 10: Дублирование кода в запросах

 

 

Один из примеров – дублирование кода. Это словосочетание привычнее слышать в контексте объектной модели, когда в разных методах встречаются одинаковые куски логики, дополненные чем-то еще. Там все очевидно: такие совпадающие фрагменты нужно выносить в отдельный метод.

В запросах ситуация немного другая. Здесь дублирование не всегда бросается в глаза, но бывает настолько явным, что совпадения видны буквально «до степени смешения».

Я сейчас сознательно не говорю о мелочах в данном примере: например, о скобках, которые появляются только потому, что в условиях перепутаны местами поля. Или о том, что корректнее сначала получить ключи аналитики, отобрать данные по ним, а уже потом соединять таблицы, вместо того чтобы сразу вставлять разыменование прямо в условие соединения.

Общий смысл в том, что мы можем из большого регистра сведений сделать выборку и уже потом отдельно поработать с результатом. Отдельно взять текущую коллекцию, отдельно взять предыдущую коллекцию, как на иллюстрации ниже.

 

 

К сожалению, невозможно показать весь запрос целиком – с тем, что сверху и снизу, например, как формировалась таблица ВТ_КоллекцииКлючиАналитики и так далее.

Но суть видна и на фрагменте. Наверху мы собрали во временную таблицу ВТ_КоллекцииКлючиАналитики коллекции отдельно и ключи аналитики отдельно, затем соединились с временной таблицей регистра СрезПоследних. При этом сделали отбор в параметрах виртуальной таблицы – как и рекомендует вендор.

Дальше мы работаем с общей таблицей ВТ_ЦеныИзПрайсЛиста. Например, можно взять коллекции из ВТ_СоставСпецификации и, отдельно, коллекции из таблицы ВТ_ПрошлаяКоллекция. Скорее всего, это будут не две разные выборки (как в исходном примере), а одна, в которой будет два ЕСТЬNULL и два соединения.

 

Пример 11: Неочевидное дублирование в объединении

 

 

Общее правило, которое у нас сложилось: если мы видим в запросе строки, которые плюс-минус совпадают, – это всегда повод внимательнее посмотреть, что там происходит.

В данном примере вместо того, чтобы сначала сделать объединение и уже потом соединить его с виртуальной таблицей регистра (причем с параметрами отбора), все реализовано иначе: без параметров отбора дважды используется громоздкий срез последних в объединении.

 

Пример 12: Неоднозначность интерпретации и соединение с шапкой

 

В качестве примера явное соединение с шапкой объекта при наличии прямого соединения с его табличной частью (по полю Ссылка) вместо неявного при использовании разыменования.

 

 

Неоднозначность интерпретации – скользкий случай.

Сначала я обрадовался, когда нашел такой прием, но потом понял, что он применим не всегда. Не во всех ситуациях можно связать табличную часть с «шапкой». Например, если табличная часть соединяется только по своим внутренним полям, то этот вариант не сработает.

 

 

В примере же табличная часть соединена по ссылке, и то самое неявное соединение (из-за разыменования в условии) мы можем явно оформить: сделать соединение с «шапкой» объекта и уже без разыменования наложить условие на нужное свойство.

Здесь используется левое соединение – оно быстрее, чем внутреннее. И мы понимаем, что в 1С табличная часть не может существовать отдельно от «шапки». Поэтому просто пользуемся этой особенностью. Sonar, конечно, будет ругаться – но в данном случае это ожидаемо.

 

Пример 13: Поля из других таблиц и вложенные соединения

 

 

Представим ситуацию: у нас два соединения. У первого соединения все хорошо. Второе соединение идет со справочником. Первое условие в нем тоже нормальное, но вот второе условие подтянуло поле из таблицы ВТ_РеквизитыДокумента. В итоге получается, что третья таблица соединяется через поле из второй.

Мы внутри команды договорились так не делать. В свое время вокруг этого вопроса было сломано много копий – и в ERP-команде, и в нашей, и между командами в компании. К единому выводу все равно не пришли, поэтому это остается на уровне договоренности.

 

 

Для понимания: конструктор в 1С неспроста ставит скобки, когда мы соединяем с третьей таблицей. Он подсказывает, что что-то здесь не так. В нашем случае первая таблица справа – это реквизиты документа, вторая – «цветомодели». Когда мы соединяемся с ней через поле второй таблицы, на деле это означает вложенное соединение.

Вендор настоятельно рекомендует такие вложенные соединения не использовать: якобы они превращаются в подзапросы. Смоделировать это на практике у меня не получилось. Примера, когда соединение действительно бы превратилось в подзапрос, привести не могу. Но договоренность внутри компании все же есть: вложенные соединения мы не делаем. Это правило фактически сквозное для всех команд.

 

Пример 14: Рабочий пример

 

 

Что мы видим:

  • В запросе есть два левых соединения.

  • Третья таблица соединяется через вторую, причем условие идет по полю из второй таблицы.

  • При этом фактически мы соединяемся с одной и той же таблицей – «Товары из заказа клиента».

В таком варианте, на мой взгляд, это допустимо. Возможно, даже обоснованно. По крайней мере, мою картину мира такой пример не ломает и в наш чек-лист как «ошибка» не попадает.

Но повторюсь: все это остается на уровне командных договоренностей. Где-то подобное решение могут забраковать, а где-то – принять как норму.

 

Рекомендации и полезные ссылки

 

Доклады, которые меня вдохновили:

  1. Дмитрий Дудин. SQL для 1С: пишем правильно, красиво, сложно – IE 2019. www.youtube.com/watch?v=e-NyKYgP0xo

  2. Артем Кузнецов. Быстрый фронт в базе размером 6.8 терабайт – наши стандарты при разработке и рефакторинге запросов – IE 2021 Moscow Premiere. www.youtube.com/watch?v=oGEu44LolFA

Наиболее часто используемый в работе стандарт:

Ограничения на соединения с вложенными запросами и виртуальными таблицами https://its.1c.ru/db/v8std#content:655:hdoc + все, что «выше» – в этом разделе стандартов 1С https://its.1c.ru/db/v8std#browse:13:-1:26:28

 

*************

Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TECH EVENT.

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта 1С v8.3 Управляемые формы Запросы Система компоновки данных Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

15500 руб.

02.09.2020    222004    1211    415    

1062

Рефакторинг и качество кода Программист Россия Бесплатно (free)

GRASP-паттерны в 1С: меньше хаоса, больше архитектуры.

28.08.2025    9821    lapinio    46    

58

Инструментарий разработчика Запросы Программист 1С v8.3 Сложные периодические расчеты Запросы 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

QueryConsole1C — расширение, включающее консоль запросов с поддержкой исполняемых представлений — аналогов виртуальных таблиц, основанных на методах программного интерфейса ЗУП. Оно позволяет выполнять запросы с учётом встроенной бизнес-логики, отлаживать алгоритмы получения данных и автоматически генерировать код на встроенном языке 1С.

1 стартмани

16.05.2025    6535    94    zup_dev    21    

72

Рефакторинг и качество кода Программист Стажер Бесплатно (free)

Разбираем принципы SOLID в контексте 1С: как укротить хаос в коде, сделать его гибким, расширяемым и предсказуемым. Практические примеры, механизмы платформы помогающие в этом и шаги к чистой разработке для новичков и профи.

21.04.2025    16879    RPGrigorev    31    

56

Нейросети Рефакторинг и качество кода Тестирование QA Программист 1С v8.3 Бесплатно (free)

Искусственный интеллект в код-ревью – это не фантастика, а реальность, которая уже сегодня помогает разработчикам улучшать свои проекты. Расскажем о том, как ИИ может автоматически находить баги и предлагать улучшения, экономя ваше время и ресурсы.

11.03.2025    10954    mrXoxot    53    

56

Инструментарий разработчика Рефакторинг и качество кода Программист 1С v8.3 Бесплатно (free)

Расширяемый форматтер структуры модулей 1С. Умеет автоматически расставлять стандартные области и раскидывать по ним процедуры и функции модуля, оформлять стандартные комментарии к методам с помощью ИИ. Также умеет анализировать модуль - извлекать структуру вызовов, используемые поля и т.д. Реализован в виде расширения (.cfe). Можно использовать как платформу для обработки кода в своих задачах автоматизации разработки.

12.02.2025    11983    694    wonderboy    49    

138

Запросы Программист Бесплатно (free)

Увидел cheatsheet по SQL и захотелось нарисовать подобное, но про запросы.

18.10.2024    18180    sergey279    18    

72

Запросы Программист 1С v8.3 Запросы 1C:Бухгалтерия Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    12860    XilDen    38    

107
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. DmitryKSL 175 28.10.25 13:51 Сейчас в теме
Раз никто не пишет просто спрошу.
Зачем писать:
ГДЕ
   ДокументСпецификацияТЗК.ПометкаУдаления = ЛОЖЬ
   И ДокументИнвойс.Проведен = ИСТИНА


Если можно так?
ГДЕ
   Не ДокументСпецификацияТЗК.ПометкаУдаления
   И ДокументИнвойс.Проведен
Трактор; sanches; +2 Ответить
2. vaillant 28.10.25 14:16 Сейчас в теме
(1) это чистая вкусовщина) (типа так быстрее, вроде у Артёма было в докладе)
5. shard 282 28.10.25 19:57 Сейчас в теме
(2) а как же указание 1с
Логические значения (например, результат логического выражения, значение, возвращаемое методом, значения переменных типа Булево) не следует проверять путем сравнения их с литералами Истина и Ложь.
3. Трактор 1272 28.10.25 17:36 Сейчас в теме
(1) Это к примеру 12, как я понял.
Я бы исходный запрос вообще не менял. Автор решил сделать красиво - его право.
Но нет предела совершенству. Если уж менять, то на внутреннее соединение и условие в нём прописать. Так будет ещё красивше.
4. alex_sayan 66 28.10.25 19:27 Сейчас в теме
С запросами две основные проблемы:
1. Их делают чрезмерно быльшими
2. В запросы пихают бизнес-логику
А остальное это мелкие технические недочеты
Для отправки сообщения требуется регистрация/авторизация