framework_eng/skills/bsl-practices/query-optimize/SKILL.md
MUST use WHEN you need to speed up an existing query or rewrite a DCS dataset. Provides rules for eliminating query-in-loop, dot-dereference, virtual tables without parameters, and excessive totals.
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.
A skill for optimizing existing queries and data composition schemas. For writing queries from scratch - query-patterns. For DB diagnostics (plan, locks, evidence) - db-performance.
db-performance ← lower evidentiary layer (DB evidence, plan, locks)
↓ passes query + reason
query-optimize ← rewrite (this skill)
↓ uses writing rules
query-patterns ← basic patterns (parameterization, NULL, loops)
Without db-performance evidence, optimization is a guess. If the cause is unknown, start with db-performance.
rg "Запрос.Текст\s*=" --type-add "bsl:*.bsl" -t bsl.xml schema through code-navigation, determine the datasetBefore rewriting, check the metadata object structure:
Tool: code-navigation → object structure.
Choose from the categories (one per iteration):
| Cause | Sign |
|---------|---------|
| Broad virtual table read | Остатки() / Обороты() without period or dimension parameters |
| Query-in-loop | Query inside Для Каждого / Пока / recursion |
| Dot-dereference without ВЫРАЗИТЬ | Движения.Регистратор.Контрагент when the type is composite |
| Excessive temp tables | Intermediate tables with a full field set instead of a minimal one |
| Extra totals | ИТОГИ in the query when a flat result set is needed |
| Filtering after join | ГДЕ conditions on fields of a large table instead of virtual table parameters |
| Implicit row multiplication through JOIN | LEFT JOIN without aggregation duplicates rows |
| DISTINCT masks the problem | ВЫБРАТЬ РАЗЛИЧНЫЕ hides an unnecessary JOIN instead of fixing it |
For each cause, use the specific rule (see the "Rules" section below).
v8-runner after any changeРАЗРЕШЕННЫЕ filters; preserve safety rulesIf the change affects the DB plan (index, virtual table parameters, join type), ask the user for EXPLAIN / trace logs before and after. Without measurement, record it as "expected effect, requires verification."
Problem: The DB computes all data first, then filters in ГДЕ.
// ПЛОХО — фильтр в WHERE, СУБД читает всё
"ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Ост
|ГДЕ Ост.Номенклатура В (&Список)"
// ХОРОШО — параметры внутри виртуальной таблицы
"ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(
| &ДатаОстатков,
| Номенклатура В (&Список) И Склад = &Склад
| ) КАК Ост"
Rule: the virtual table always receives period and dimension parameters. The only exception is an explicit justification (a report for all warehouses without a filter).
Problem: N iterations × (latency + query time).
// ПЛОХО — запрос в цикле
Для Каждого Строка Из Документ.Товары Цикл
Запрос.УстановитьПараметр("Ном", Строка.Номенклатура);
// ... выполнить запрос
КонецЦикла;
// ХОРОШО — один запрос, Соответствие для доступа
МассивНом = Документ.Товары.ВыгрузитьКолонку("Номенклатура");
Запрос.УстановитьПараметр("Список", МассивНом);
// ... один запрос
РезСоответствие = Новый Соответствие;
Пока Выборка.Следующий() Цикл
РезСоответствие.Вставить(Выборка.Ссылка, Выборка);
КонецЦикла;
Для Каждого Строка Из Документ.Товары Цикл
Данные = РезСоответствие.Получить(Строка.Номенклатура);
КонецЦикла;
Problem: Движения.Регистратор.Контрагент when the type is composite - the DB performs a LEFT JOIN to all tables of the composite type.
// ПЛОХО — N LEFT JOIN по составному типу
"ВЫБРАТЬ Движения.Регистратор.Контрагент ..."
// ХОРОШО — один JOIN
"ВЫБРАТЬ
| ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент
|...
|ГДЕ Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг"
// Только поля, нужные следующим этапам
"ВЫБРАТЬ
| Реализация.Ссылка КАК Документ,
| Реализация.Контрагент КАК Контрагент
|ПОМЕСТИТЬ втРеализации
|...
|ИНДЕКСИРОВАТЬ ПО Контрагент" // только поле соединения
Rule: use ИНДЕКСИРОВАТЬ ПО for fields that will be used in a JOIN in the next query of the package. Do not add an index on every field.
ИТОГИ generates extra total rows. If a flat result set is needed, use СГРУППИРОВАТЬ ПО.
// ИТОГИ нужны только при иерархическом обходе Выбрать(ПоГруппировкам)
// Для плоской выборки — только СГРУППИРОВАТЬ ПО
"ВЫБРАТЬ Контрагент, СУММА(Сумма) КАК Итог
|ИЗ ...
|СГРУППИРОВАТЬ ПО Контрагент"
// ПЛОХО — JOIN умножает строки, РАЗЛИЧНЫЕ скрывает
"ВЫБРАТЬ РАЗЛИЧНЫЕ Контрагенты.Ссылка
|ИЗ Справочник.Контрагенты КАК Контрагенты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.Реализация КАК Реал
| ПО Контрагенты.Ссылка = Реал.Контрагент"
// ХОРОШО — подзапрос
"ВЫБРАТЬ Контрагенты.Ссылка
|ИЗ Справочник.Контрагенты КАК Контрагенты
|ГДЕ Контрагенты.Ссылка В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ Реал.Контрагент
| ИЗ Документ.Реализация КАК Реал)"
СВЯЗЬ) with conditions and no index on the detail side - check metadataГДЕ)ИНДЕКСИРОВАТЬ ПО)ВЫРАЗИТЬ before dot-dereferenceЛЕВОЕ СОЕДИНЕНИЕ does not turn into ВНУТРЕННЕЕ because of a condition in ГДЕРАЗЛИЧНЫЕ does not mask an unnecessary JOINРАЗРЕШЕННЫЕ and other rights filters are preservedРАЗРЕШЕННЫЕ without explicit security approval.db-performance task.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.