← Назад к вопросам
Анализ и оптимизация медленного SQL-запроса
3.0 Senior🔥 131 комментариев
#Запросы и оптимизация#Регистры
Условие
Вам дан медленный запрос к регистру накопления. Проанализируйте и оптимизируйте его.
ВЫБРАТЬ
Товары.Номенклатура,
Товары.Номенклатура.Наименование,
СУММА(Товары.Количество) КАК Количество
ИЗ
РегистрНакопления.ОстаткиТоваров КАК Товары
ГДЕ
Товары.Период >= &НачалоПериода
И Товары.Период <= &КонецПериода
СГРУППИРОВАТЬ ПО
Товары.Номенклатура
Задание
- Найдите проблемы в запросе
- Предложите оптимизированную версию
- Объясните, почему ваша версия быстрее
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Часть 1: Анализ проблем в исходном запросе
// ИСХОДНЫЙ ЗАПРОС (медленный):
ВЫБРАТЬ
Товары.Номенклатура,
Товары.Номенклатура.Наименование, // ← ПРОБЛЕМА 1
СУММА(Товары.Количество) КАК Количество
ИЗ
РегистрНакопления.ОстаткиТоваров КАК Товары // ← ПРОБЛЕМА 2
ГДЕ
Товары.Период >= &НачалоПериода // ← ПРОБЛЕМА 3
И Товары.Период <= &КонецПериода
СГРУППИРОВАТЬ ПО
Товары.Номенклатура
Проблема 1: Доступ к реквизитам справочника в SELECT
Товары.Номенклатура.Наименованиетребует дополнительной выборки из Справочника- Это вызывает N+1 запросов: один к регистру, потом N к справочнику
- Очень медленно при большом количестве товаров
Проблема 2: Чтение ВСЕХ строк регистра
РегистрНакопления.ОстаткиТоваровхранит ВСЕ движения- Если товаров миллионы, это будет очень долгая выборка
- Нужно использовать виртуальную таблицу .Остатки
Проблема 3: Фильтр по двум условиям вместо одного интервала
>= И <=медленнее, чем использовать МЕЖДУ- Индекс по Период + Вид Движения не будет использован эффективно
Часть 2: Оптимизированная версия
// ОПТИМИЗИРОВАННЫЙ ЗАПРОС:
ВЫБРАТЬ
Номенклатура.Ссылка КАС Номенклатура,
Номенклатура.Наименование,
СУММА(Остатки.Количество) КАС Количество
ИЗ
РегистрНакопления.ОстаткиТоваров.Остатки(
&КонецПериода,
Номенклатура
) КАС Остатки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАС Номенклатура
ПО Остатки.Номенклатура = Номенклатура.Ссылка
СГРУППИРОВАТЬ ПО
Номенклатура.Ссылка,
Номенклатура.Наименование
ПОРЯДОКПО
Номенклатура.Наименование
Улучшения:
-
Виртуальная таблица .Остатки вместо прямого доступа к регистру
- Использует индексы БД для быстрого поиска
- Автоматически считает остатки
- Параметр
&КонецПериода— дата состояния
-
ВНУТРЕННЕЕ СОЕДИНЕНИЕ со справочником вместо доступа через точку
- SQL выполняет джойн эффективно
- Все данные получаются одним запросом
- Избегаем N+1 проблемы
-
Убран интервал начало-конец
- Виртуальная таблица сама вычисляет остаток на дату
- Не нужны границы интервала
Часть 3: Версия с фильтром по периоду (если нужны именно движения)
// ЕСЛИ НУЖНЫ ДВИЖЕНИЯ в интервале (не остатки):
ВЫБРАТЬ
Номенклатура.Ссылка,
Номенклатура.Наименование,
СУММА(Движения.Количество) КАС КоличествоДвижений
ИЗ
РегистрНакопления.ОстаткиТоваров КАС Движения
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАС Номенклатура
ПО Движения.Номенклатура = Номенклатура.Ссылка
ГДЕ
Движения.Период МЕЖДУ &НачалоПериода И &КонецПериода
СГРУППИРОВАТЬ ПО
Номенклатура.Ссылка,
Номенклатура.Наименование
ПОРЯДОКПО
Номенклатура.Наименование
Улучшения:
МЕЖДУвместо>= И <=— БД лучше оптимизирует- ВНУТРЕННЕЕ СОЕДИНЕНИЕ с отдельной выборкой справочника
- Группировка по обоим полям для корректного результата
Часть 4: Версия с регистром сведений (самая быстрая)
// ЕСЛИ ЕСТЬ регистр сведений с кэшем остатков:
ВЫБРАТЬ
КэшОстатков.Номенклатура,
Номенклатура.Наименование,
КэшОстатков.Количество
ИЗ
РегистрСведений.ОстаткиНаДату КАС КэшОстатков // специальный регистр
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАС Номенклатура
ПО КэшОстатков.Номенклатура = Номенклатура.Ссылка
ГДЕ
КэшОстатков.Дата = &Дата
ПОРЯДОКПО
Номенклатура.Наименование
Причина скорости:
- Кэш вычисляется один раз (регламентное задание)
- Регистр сведений намного меньше и быстрее
- Один простой запрос с простым индексом
- Идеально для отчётов, которые создаются часто
Часть 5: Сравнение производительности
| Запрос | Сложность | Скорость | Когда использовать |
|---|---|---|---|
| Исходный | O(N²) | 100% (медленно) | НЕ ИСПОЛЬЗОВАТЬ |
| Оптимизированный 1 (Остатки) | O(N) | 10-15% | Остатки на дату |
| Оптимизированный 2 (МЕЖДУ) | O(N·log N) | 25-30% | Движения за период |
| Оптимизированный 3 (Кэш) | O(N) | 1-2% | Частые отчёты |
Часть 6: Проверка использования индексов
// В 1С можно проверить план выполнения запроса:
// Конфигуратор → Запрос → Анализ → Выполнить
// Хороший план должен содержать:
// ✓ Index Seek по Период
// ✓ Hash Aggregate для GROUP BY
// ✓ Hash Join для СОЕДИНЕНИЯ
// Плохой план содержит:
// ✗ Table Scan (полное сканирование)
// ✗ Nested Loop (циклический джойн)
// ✗ Sort (сортировка вместо индекса)
Часть 7: Рекомендации по индексам
// В регистре накопления "ОстаткиТоваров" нужны индексы:
// 1. Первичный индекс (по умолчанию)
// Период, ВидДвижения, Номенклатура
// 2. Дополнительный индекс
// (Период, Номенклатура) INCLUDE (Количество)
// 3. Для быстрой выборки остатков
// (Номенклатура, Период DESC) INCLUDE (Количество)
Ключевые принципы оптимизации:
1. Используй виртуальные таблицы регистров:
.Остаткивместо прямого доступа к регистру- БД сама оптимизирует индексы
2. Джойни в SQL, не в коде:
- Не доступи через точку в SELECT
- Используй СОЕДИНЕНИЕ с отдельной таблицей
3. Фильтруй в WHERE по индексам:
- МЕЖДУ вместо >= И <=
- Точные условия вместо LIKE если возможно
4. Группируй и сортируй правильно:
- GROUP BY по всем полям из SELECT
- ORDER BY по индексам
5. Кэшируй вычисляемые данные:
- Для отчётов создавай регистр сведений
- Пересчитывай регламентным заданием
6. Проверяй план выполнения:
- Используй встроенный анализатор запросов
- Смотри, какие индексы используются