Сравнение двух запросов 1С: текст, результат и скорость
Содержание
Сравнить два запроса в 1С можно на трёх уровнях: текст (чем отличается код), результат (одинаковые ли данные они отдают) и скорость (какой план выполнения строит СУБД). Под каждый уровень — свой инструмент: для текста берут diff-утилиту, для результата соединяют наборы через временные таблицы, для скорости снимают SQL технологическим журналом и смотрят план на стороне базы данных.
Какой уровень вам нужен, подсказывает задача. После рефакторинга проверяют, что переписанный запрос возвращает ровно те же строки. При оптимизации сравнивают два варианта по времени и плану. При чистке конфигурации ищут повторяющийся код запросов, чтобы вынести его в одну функцию.
Текстовое сравнение запросов в Конфигураторе и EDT
Отдельной кнопки «сравнить два запроса» в конструкторе запроса нет. Конструктор показывает и форматирует текст одного запроса, но не умеет сопоставлять два. Поэтому тексты сравнивают внешними средствами или через механизмы сравнения модулей.
Самый быстрый путь для разовой проверки:
- Откройте первый запрос в конструкторе, нажмите кнопку автоформатирования (выравнивает отступы и регистр ключевых слов), скопируйте текст.
- То же со вторым запросом.
- Вставьте оба текста в diff-инструмент и смотрите подсвеченные различия построчно.
Автоформатирование перед сравнением критично: без него diff покажет разницу там, где отличаются только пробелы и переносы строк, а не смысл. Приведите оба текста к одному стилю — тогда останутся только реальные отличия.
Для diff подойдут бесплатные WinMerge, KDiff3, Meld, плагин Compare в Notepad++ или встроенное сравнение в VS Code. Они красят изменённые, добавленные и удалённые строки разными цветами и позволяют листать различия по одному.
Если запросы лежат в модулях конфигурации, работает штатное сравнение 1С. Конфигурация → Сравнить, объединить с конфигурацией из файла сопоставляет две конфигурации целиком и внутри изменённых модулей показывает текстовый diff — в том числе строки запроса. Так удобно сравнивать запрос в рабочей базе и в обновлённой поставке.
В 1С:EDT сравнение встроено глубже. Редактор хранит модули как файлы и показывает различия через Git прямо в окне: левая и правая версия, цветные блоки. Для запроса, собранного схемой запроса (СхемаЗапроса), EDT сравнивает его сериализованное представление.
Если нужно сравнить не весь модуль, а только текст запроса из строки, вынесите его во временную переменную или в макет — тогда diff не будет спотыкаться об окружающий код обработки.
Проверка, что два запроса дают одинаковый результат
Текст может отличаться, а данные совпадать — и наоборот. Чтобы убедиться, что переписанный запрос эквивалентен исходному, сравнивают не код, а наборы строк.
Приём: поместить результаты обоих запросов во временные таблицы одного пакетного запроса, а затем соединить их полным соединением по ключевым полям. Строки, которые есть только в одном наборе, и строки с разными значениями всплывут сразу.
ВЫБРАТЬ
Номенклатура КАК Номенклатура,
Количество КАК Количество
ПОМЕСТИТЬ ВТ_Запрос1
ИЗ
// ... первый запрос ...
;
ВЫБРАТЬ
Номенклатура КАК Номенклатура,
Количество КАК Количество
ПОМЕСТИТЬ ВТ_Запрос2
ИЗ
// ... второй запрос ...
;
ВЫБРАТЬ
ЕСТЬNULL(Т1.Номенклатура, Т2.Номенклатура) КАК Номенклатура,
Т1.Количество КАК КоличествоПервый,
Т2.Количество КАК КоличествоВторой
ИЗ
ВТ_Запрос1 КАК Т1
ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Запрос2 КАК Т2
ПО Т1.Номенклатура = Т2.Номенклатура
ГДЕ
Т1.Номенклатура ЕСТЬ NULL
ИЛИ Т2.Номенклатура ЕСТЬ NULL
ИЛИ Т1.Количество <> Т2.Количество
Логика финального запроса читается так:
Т1.Номенклатура ЕСТЬ NULL— строка есть во втором наборе, но не в первом.Т2.Номенклатура ЕСТЬ NULL— строка есть в первом, но не во втором.Т1.Количество <> Т2.Количество— строка есть в обоих, но значения разошлись.
Если итоговый результат пуст — по этим полям запросы эквивалентны. Любая строка в выборке — это расхождение, которое нужно разобрать.
Пара нюансов, из-за которых метод иногда «врёт»:
- Ключом соединения должны быть все поля, однозначно определяющие строку. Если соединить только по номенклатуре, а в данных есть разбивка по складам, совпадения склеятся и часть различий спрячется.
- Сравнение чисел с плавающей частью лучше вести через разность с допуском (
АвтономныйДопуск), а не строгим<>— иначе округление даст ложные расхождения. NULLи пустая ссылка (Справочники.Номенклатура.ПустаяСсылка()) — не одно и то же. Если один запрос отдаёт пустую ссылку, а другойNULL, оберните оба вЕСТЬNULLк общему значению.
Прогнать пакетный запрос удобно в консоли запросов — штатной обработке «Консоль запросов» с диска ИТС или аналоге из EDT. Она же покажет оба промежуточных набора по отдельности.
Запрос только читает данные, но тяжёлые виртуальные таблицы на больших регистрах всё равно нагружают сервер. Для объёмных сравнений берите копию базы, а не рабочую.
Сравнение запросов по скорости: планы выполнения
Два запроса с одинаковым результатом могут различаться по времени в десятки раз. Разницу видно по плану выполнения, который строит СУБД.
Платформа 1С сама SQL-план не показывает — запрос на языке 1С транслируется в SQL, и план строит уже сервер базы данных. Чтобы его получить, нужны два шага: снять реальный SQL и прогнать его средствами СУБД.
Шаг 1. Снять SQL технологическим журналом. Разместите файл logcfg.xml в каталоге conf установленной платформы (рядом с исполняемыми файлами 1cv8) и настройте сбор события DBMSSQL:
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\tj" history="4">
<event>
<eq property="name" value="DBMSSQL"/>
</event>
<property name="all"/>
</log>
</config>
В событии DBMSSQL будет полный текст SQL и длительность (Durationus). Выполните сначала первый запрос, затем второй — и сопоставьте их по времени и объёму чтений.
Технологический журнал заметно нагружает сервер и быстро растит файлы — включайте его точечно под конкретный замер и выключайте сразу после.
Шаг 2. Сравнить планы средствами СУБД. Возьмите SQL из журнала и постройте план на стороне базы:
MS SQL Server: в SSMS включите «Фактический план выполнения» (Ctrl+M) и выполните оба запроса. Планы покажут, где идёт сканирование таблицы вместо поиска по индексу. ПолезныSET STATISTICS IO ONиSET STATISTICS TIME ON— они дают число логических чтений и время.PostgreSQL: выполнитеEXPLAIN (ANALYZE, BUFFERS) <запрос>;. В выводе видно, сколько строк реально прочитано и где узкое место.
Что сравнивать в двух планах:
- Поиск по индексу против сканирования таблицы. Index Seek (MS SQL) или Index Scan по нужному индексу — хорошо; Table Scan или Seq Scan на большой таблице — сигнал, что запросу не хватает индекса или условие отбора не попадает в индекс.
- Способ соединения. Hash Join на больших наборах обычно уместен, Nested Loops по многотысячным строкам — часто источник тормозов.
- Число реально прочитанных строк. Если план ожидал десятки строк, а прочитал миллионы, статистика устарела или условие отбора неселективно.
Для быстрой прикидки, какой из двух запросов в коде тормозит, не поднимая журнал, подойдёт Отладка → Замер производительности в Конфигураторе. Он покажет время по строкам встроенного языка, но не сам SQL-план. Углублённые замеры с планами собирает Центр управления производительностью из состава КИП.
Поиск дублирующихся запросов в конфигурации
Когда задача не «сравнить два конкретных запроса», а «найти, где один и тот же запрос повторяется», работает глобальный поиск по текстам.
- В Конфигураторе откройте
Правка → Глобальный поиск(Ctrl+Shift+F). - Ищите характерный фрагмент: имя таблицы (
РегистрНакопления.ТоварыНаСкладах), устойчивую конструкцию или кусок условия. - Пройдите по совпадениям — одинаковые или почти одинаковые запросы в разных модулях и есть кандидаты на вынос в общую функцию.
Глобальный поиск находит точные вхождения, но не замечает запросы, которые отличаются форматированием или порядком полей. Для такого ищут по нескольким опорным фрагментам и просматривают результаты глазами.
Систематически дубли и антипаттерны запросов отлавливают статические анализаторы: SonarQube с плагином для 1С и проверки в 1С:EDT. Они разбирают код и помечают повторяющиеся или потенциально медленные конструкции — например, соединение с вложенным запросом или обращение к виртуальной таблице в цикле.
Нашли дубль — выносите общий запрос в функцию общего модуля, принимающую параметры отбора. Тогда исправлять и оптимизировать придётся одно место, а не десять.
Различия СУБД, которые влияют на сравнение
Один и тот же запрос 1С на разных СУБД превращается в разный SQL и строит разные планы. Поэтому сравнение «какой быстрее» имеет смысл только в пределах той базы данных, где крутится продуктив.
На что это влияет на практике:
| Аспект | MS SQL Server | PostgreSQL |
|---|---|---|
| Ограничение выборки | ВЫБРАТЬ ПЕРВЫЕ → TOP | ВЫБРАТЬ ПЕРВЫЕ → LIMIT |
| Чувствительность к устаревшей статистике | умеренная | высокая, нужен регулярный ANALYZE |
| Типичная засада плана | parameter sniffing (план под «не тот» параметр) | недооценка числа строк без свежей статистики |
| Временные таблицы | в tempdb, нужны индексы | локальные temp, тоже нужны индексы |
Общие правила, которые помогают обоим серверам одинаково:
- Индексируйте временные таблицы по полям соединения через
ИНДЕКСИРОВАТЬ ПО— иначе соединение больших наборов уходит в полный перебор. - Не соединяйте таблицу с подзапросом: сначала положите подзапрос во временную таблицу, потом соединяйте.
- Избегайте запросов в цикле — один пакетный запрос почти всегда быстрее серии мелких.
Отдельная история — файловый режим. Там своя встроенная СУБД, SQL-плана в привычном виде нет, и технологический журнал план по файловой базе не отдаст. Сравнивать скорость в файловой базе можно только по общему времени выполнения и замеру производительности. Выводы из файловой базы нельзя автоматически переносить на клиент-серверную, и наоборот.
Сравнение версий запроса и автоматизация
Когда запрос правят со временем, сравнивать приходится не два файла, а две версии одного и того же модуля. Это задача системы контроля версий.
Хранилище конфигурации. В Конфигураторе откройте историю объекта и сравните две версии модуля — платформа покажет текстовый diff, включая изменённые строки запроса. Так видно, кто и когда переписал запрос и что именно поменялось.
Git. 1С:EDT работает с Git нативно: история коммитов, сравнение версий, ветки. Для конфигураций, которые ведут в Конфигураторе, применяют выгрузку в файлы (Конфигурация → Выгрузить конфигурацию в файлы) и внешние утилиты вроде precommit1c / gitsync — они кладут модули в репозиторий, и дальше diff делает сам Git.
Автоматизацию проверки эквивалентности строят на тестах. Сценарий такой: тест прогоняет старый и новый запрос на одних входных данных и сравнивает наборы тем же полным соединением, что описано выше. Если расхождений нет — тест зелёный. Такие проверки запускают сценарным тестированием (Vanessa Automation) или юнит-тестами и ставят в CI, чтобы они срабатывали на каждый коммит.
Минимальный рабочий набор под регулярное сравнение запросов:
Частые вопросы
Можно ли сравнить два запроса прямо в конструкторе запроса?
Запросы возвращают разные данные — с чего начать разбор?
ЛЕВОЕ против ВНУТРЕННЕГО) или в условии ГДЕ.Почему один и тот же запрос быстрый на MS SQL и медленный на PostgreSQL?
ANALYZE. На MS SQL частая причина — parameter sniffing. Сравнивать скорость нужно на той СУБД, что стоит в продуктиве.Виден ли план запроса в файловой базе?
Замер производительности в Конфигураторе.