framework/skills/bsl-practices/query-optimize/SKILL.md
MUST use WHEN нужно ускорить существующий запрос или переписать СКД dataset. Provides правила устранения query-in-loop, dot-dereference, виртуальных таблиц без параметров и излишних итогов.
npx skillsauth add steelmorgan/1c-agent-based-dev-framework query-optimizeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Навык для оптимизации существующих запросов и схем компоновки данных. Для написания запросов с нуля — query-patterns. Для СУБД-диагностики (план, блокировки, evidence) — db-performance.
db-performance ← нижний доказательный слой (СУБД-evidence, план, блокировки)
↓ передаёт запрос + причину
query-optimize ← переписывание (этот навык)
↓ использует правила написания
query-patterns ← базовые паттерны (параметризация, NULL, циклы)
Без db-performance-evidence оптимизация — предположение. Если причина неизвестна — сначала db-performance.
rg "Запрос.Текст\s*=" --type-add "bsl:*.bsl" -t bsl.xml схемы через code-navigation, определить набор данныхПрежде чем переписывать — проверить структуру объекта метаданных:
Инструмент: code-navigation → структура объекта.
Выбрать из категорий (одну на итерацию):
| Причина | Признак |
|---------|---------|
| Широкое чтение виртуальной таблицы | Остатки() / Обороты() без параметров периода или измерений |
| Query-in-loop | Запрос внутри Для Каждого / Пока / рекурсии |
| Dot-dereference без ВЫРАЗИТЬ | Движения.Регистратор.Контрагент при составном типе |
| Избыточные временные таблицы | Промежуточные таблицы с полным набором полей вместо минимального |
| Лишние итоги | ИТОГИ в запросе, когда нужна плоская выборка |
| Фильтрация после соединения | Условия ГДЕ на полях большой таблицы вместо параметров виртуальной таблицы |
| Неявное умножение строк через JOIN | LEFT JOIN без агрегации дублирует строки |
| РАЗЛИЧНЫЕ маскирует проблему | ВЫБРАТЬ РАЗЛИЧНЫЕ скрывает лишний JOIN вместо его исправления |
Для каждой причины — конкретное правило (см. раздел «Правила» ниже).
v8-runner после любого измененияРАЗРЕШЕННЫЕ не убирать молча, правила безопасности сохраняютсяЕсли изменение влияет на план СУБД (индекс, параметры виртуальной таблицы, тип соединения) — запросить у пользователя EXPLAIN / ТЖ до и после. Без измерения — зафиксировать как «ожидаемый эффект, требует проверки».
Проблема: СУБД вычисляет все данные, потом фильтрует в ГДЕ.
// ПЛОХО — фильтр в WHERE, СУБД читает всё
"ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Ост
|ГДЕ Ост.Номенклатура В (&Список)"
// ХОРОШО — параметры внутри виртуальной таблицы
"ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(
| &ДатаОстатков,
| Номенклатура В (&Список) И Склад = &Склад
| ) КАК Ост"
Правило: виртуальная таблица всегда получает параметры периода и измерений. Исключение только при явном обосновании (отчёт по всем складам без фильтра).
Проблема: N итераций × (латентность + время запроса).
// ПЛОХО — запрос в цикле
Для Каждого Строка Из Документ.Товары Цикл
Запрос.УстановитьПараметр("Ном", Строка.Номенклатура);
// ... выполнить запрос
КонецЦикла;
// ХОРОШО — один запрос, Соответствие для доступа
МассивНом = Документ.Товары.ВыгрузитьКолонку("Номенклатура");
Запрос.УстановитьПараметр("Список", МассивНом);
// ... один запрос
РезСоответствие = Новый Соответствие;
Пока Выборка.Следующий() Цикл
РезСоответствие.Вставить(Выборка.Ссылка, Выборка);
КонецЦикла;
Для Каждого Строка Из Документ.Товары Цикл
Данные = РезСоответствие.Получить(Строка.Номенклатура);
КонецЦикла;
Проблема: Движения.Регистратор.Контрагент при составном типе — СУБД делает LEFT JOIN ко всем таблицам составного типа.
// ПЛОХО — N LEFT JOIN по составному типу
"ВЫБРАТЬ Движения.Регистратор.Контрагент ..."
// ХОРОШО — один JOIN
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент
|...
|ГДЕ Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг"
// Только поля, нужные следующим этапам
"ВЫБРАТЬ
| Реализация.Ссылка КАК Документ,
| Реализация.Контрагент КАК Контрагент
|ПОМЕСТИТЬ втРеализации
|...
|ИНДЕКСИРОВАТЬ ПО Контрагент" // только поле соединения
Правило: ИНДЕКСИРОВАТЬ ПО для полей, по которым будет JOIN в следующем запросе пакета. Не добавлять индекс на все поля.
ИТОГИ генерирует дополнительные строки-суммы. Если нужна плоская выборка — использовать СГРУППИРОВАТЬ ПО.
// ИТОГИ нужны только при иерархическом обходе Выбрать(ПоГруппировкам)
// Для плоской выборки — только СГРУППИРОВАТЬ ПО
"ВЫБРАТЬ Контрагент, СУММА(Сумма) КАК Итог
|ИЗ ...
|СГРУППИРОВАТЬ ПО Контрагент"
// ПЛОХО — JOIN умножает строки, РАЗЛИЧНЫЕ скрывает
"ВЫБРАТЬ РАЗЛИЧНЫЕ Контрагенты.Ссылка
|ИЗ Справочник.Контрагенты КАК Контрагенты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Реализация КАК Реал
| ПО Контрагенты.Ссылка = Реал.Контрагент"
// ХОРОШО — подзапрос
"ВЫБРАТЬ Контрагенты.Ссылка
|ИЗ Справочник.Контрагенты КАК Контрагенты
|ГДЕ Контрагенты.Ссылка В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ Реал.Контрагент
| ИЗ Документ.Реализация КАК Реал)"
ГДЕ)ИНДЕКСИРОВАТЬ ПО)ВЫРАЗИТЬ перед dot-dereferenceЛЕВОЕ СОЕДИНЕНИЕ не превращается в ВНУТРЕННЕЕ из-за условия в ГДЕРАЗЛИЧНЫЕ не маскирует лишний JOINРАЗРЕШЕННЫЕ и прочие фильтры прав сохраненыРАЗРЕШЕННЫЕ без явного согласования безопасности.db-performance.depends_on:
testing
MUST use BEFORE making a judgment about the cause of a conflict, a test failure, or an artifact dispute. Defines the end-to-end verification method L1→L6 and the classification of the first broken link.
development
MUST use AFTER a work cycle with ≥2 iterations (wrote → error → fixed → success). Provides the retrospective procedure and the format for recording practice/anti-patterns in references/learned-patterns.md or {project}/.context/learned-patterns.md.
tools
MUST use WHEN you are writing reusable knowledge into RLM (pattern / architectural decision / stable domain fact) OR reading it before a non-trivial task/solution in the domain. Provides the breakdown of native-push vs RLM-pull, tools for writing and reading RLM, H-MEM levels, and hygiene.
testing
MUST use WHEN the task is classified as simple (< 20 lines, 1 file, no new metadata objects, no architectural decisions). Provides a short cycle of 3 steps with a guard on the self path and mandatory verify.