В современных высоконагруженных ERP-системах на платформе 1С, работающих с базами данных объемом от 1 ТБ и обслуживающих сотни и тысячи одновременно работающих пользователей, проблемы производительности запросов иногда могут приводить к серьезным последствиям для оперативной деятельности бизнеса. К одним из самых сложных случаев относятся проблемы, которые возникают время от времени и из зависят о неопределенных факторов.
В данной статье мы детально разберем реальный кейс из практики сопровождения крупной ERP-системы торговой компании, где подобная проблема вызывала массовые блокировки при обработке складских документов. Вы узнаете:
- Полную методику диагностики проблем производительности в связке 1С и PostgreSQL
- Глубокий анализ архитектурных особенностей при работе с полями с составными типами в запросах на разных уровнях (1C и СУБД PostgreSQL)
- Подробное сравнение альтернативных подходов к оптимизации
- Практические рекомендации по предотвращению подобных ситуаций на этапе разработки
1. Детальное описание проблемы
1.1. Бизнес-контекст и симптомы
Некоторая торговая компания. В пиковые периоды система испытывала нагрузки до:
- 1,400+ одновременных пользователей
Проблема проявилась в модуле складского учета при:
- Проведении приходных ордеров
- Формировании расходных накладных
- Оформлении перемещений
Пользователи получали ошибки:
«Конфликт блокировок при выполнении транзакции:
Превышено максимальное время ожидания предоставления блокировки»
1.2. Техническое окружение
Программное обеспечение:
- PostgreSQL 15.3 с настройками для 1С
- Платформа 1С:Предприятие 8.3.23.1688
Характеристики базы:
- 1С:ERP 2.5.12.112
- Общий размер: 1.8+ ТБ
2. Подтверждение и диагностика проблемы блокировок
2.1. Подтверждение и первичный анализ проблемы
В рамках сопровождения высоконагруженной ERP-системы нами реализована комплексная система мониторинга, обеспечивающая непрерывный контроль ключевых показателей производительности. Для получения таких метрик мы используем анализ событий блокировок из технологического журнала, который в нашей системе мониторинга отображается под названием «Блокировки - 1C & POSTGRES».
Информация о возникновении проблем была подтверждена. Для детального изучения мы проанализировали указанный выше замер, отфильтровав события по пользователю «Пользователь-8».

Рис.1. Список событий замеров для замера «Блокировки - 1C & POSTGRES»
Как видно на рисунке, мониторинг зафиксировал повторяющиеся события блокировок, что полностью подтверждает первоначальную проблему. Длительность этих блокировок критически сказывается на отзывчивости системы для конечных пользователей.
Для поиска корневой причины мы фокусируемся на колонке WaitConnections. Её значение показывает, какие именно соединения к СУБД не позволяет завершить операцию текущему пользователю («Пользователь-8»).
Небольшое резюме по ситуации на рисунке:
- В строке, соответствующей времени 01.04.2024 11:52:31, значение WaitConnections равно списку блокировок 23929, 18835, 239, 743. Получается что в этот момент существует небольшая очередь к нужной таблице.
- Важно отметить, что это не единичный случай. Анализ лога показывает, что на протяжении нескольких минут различные сессии ожидают освобождения ресурсов. Возьмем номер соединения 23929 для дальнейшей идентификации «виновника» (blocker) и основную цель для дальнейшей диагностики.
2.2. Поиск виновника
Чтобы определить виновника блокировки, воспользуемся полученной ранее информацией и выясним, какой сеанс и какой пользователь её вызывают.
Для этого мы используем замер «Данные 1С RAS». Этот замер хранит информацию о соединениях и сеансах пользователей и сохраняется с интервалом в 60 секунд.

Рис. Форма обработки просмотра событий соединений RAS 1C
Далее перейдём к информации на вкладке «Сеансы».

Рис. Форма обработки просмотра сеансов RAS 1C
После перехода на вкладку «Сеансы» установим отбор по номеру найденного проблемного сеанса и обратим внимание на ключевые показатели.
Нас интересует имя пользователя — в данном случае это Пользователь-171. Также стоит обратить внимание на значение в колонке «Захвачено СУБД». Этот параметр показывает время, которое пользователь занимает на получение данных из базы данных, то есть время выполнения запроса. В нашем случае оно составляет около 18 секунд.
Имея эту информацию, мы можем предположить что существует некий длительный запрос. Далее попробуем найти его среди всех замеров длительных операций. Напоминаю, что длительными считаются запросы, время выполнения которых превышает заданный порог. В нашем случае этот порог был установлен на 5 секунд.
3. Определение причины проблемы
3.1 Поиск контекста
Переходим к замеру с названием «Длительные запросы - 1C & POSTGRES». Применим отбор по пользователю и номеру сеанса, чтобы найти нужные события.

Рис. Список событий замеров для замера «Длительные запросы - 1C & POSTGRES»
Действительно, мы видим, что в это время существовал некий длительный запрос, который попал в технологический журнал. Отсюда мы можем получить ценную информацию: контекст выполнения (место в коде, откуда был вызван запрос) и текст самого SQL-запроса.

Рис. Контекст выполнения запроса
Как мы видим, проблемное событие возникает в модуле менеджера регистра накопления «Запасы и потребности». Теперь, когда мы определили источник проблемного запроса, перейдём к его анализу.
Откроем Конфигуратор, найдём соответствующий исходный код модуля и идентифицируем запрос-виновник.
ВЫБРАТЬ РАЗЛИЧНЫЕ
Товары.Номенклатура КАК Номенклатура,
Товары.Характеристика КАК Характеристика,
Товары.Склад КАК Склад,
Товары.Назначение КАК Назначение,
Товары.Заказ КАК Заказ,
Товары.ДатаСобытия КАК ДатаСобытия
ПОМЕСТИТЬ ДвиженияПриЗаписи
ИЗ
&ТаблицаТовары КАК Товары
ГДЕ
Товары.Активность
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
Товары.Номенклатура КАК Номенклатура,
Товары.Характеристика КАК Характеристика,
Товары.Склад КАК Склад,
Товары.Назначение КАК Назначение,
Товары.Заказ КАК Заказ,
Товары.ДатаСобытия КАК ДатаСобытия
ИЗ
ДвиженияПриЗаписи КАК Товары
ОБЪЕДИНИТЬ
ВЫБРАТЬ РАЗЛИЧНЫЕ
Движения.Номенклатура,
Движения.Характеристика,
Движения.Склад,
Движения.Назначение,
Движения.Заказ,
Движения.ДатаСобытия
ИЗ
РегистрНакопления.ЗапасыИПотребности КАК Движения
ГДЕ
Движения.Регистратор В(&Регистраторы)
И Движения.Активность
Перед нами — пакет запросов. Чтобы понять какой из двух запросов пакета виновен (в принципе и так можно догадаться), обратим внимание на текст SQL-запроса. И теперь сделаем вывод, что это второй запрос в этом пакете.

Рис. Текст SQL запроса
Но почему он проблемный? На первый взгляд, ничего криминального здесь нет (оператор РАЗЛИЧНЫЕ конечно же не очень хорошо, но у нас присутствует "сильный" отбор). В запросе используется фильтр по регистратору, для которого всегда существует индекс. Давайте посмотрим план запроса, чтобы выяснить в чем проблема.
3.2. Анализ плана запроса
Чтобы заглянуть под "капот" нашей системы, скопируем запрос виновник в консоль запросов и выполним его с указанием параметров. В результате у нас получится некий план запроса:
https://explain.tensor.ru/archive/explain/2a4e76547ce6fb66ed59db53312f7159:0:2024-04-14#visio
Прежде чем двигаться дальше, кратко проясним соответствие операторов плана запроса исходному коду на языке 1С.

Рис. Соответствие операторов плану запросов
- Верхняя часть плана (красный прямоугольник): Два оператора относятся к первой выборке, где данные берутся из временной таблицы.
- Оператор APPEND в связке с AGGREGATE является прямым аналогом команды «Объединить» в 1С.
- Нижняя часть плана (синий прямоугольник): Отвечает за выборку данных из регистра накопления.
Возникает вопрос: почему в нижней части мы видим еще один оператор AGGREGATE (объединение)? Мы же выбираем данные из одного источника - из регистра накопления.
На тексте запроса на языке запросов 1С этого мы не увидим. Тогда посмотрим на SQL-текст запроса. И мы там увидим кое что необычное (выделено на рисунке красным прямоугольником).

Рис. Наличие оператора ИЛИ в SQL-тексте запроса
Это объединение появляется из-за наличия в SQL запросе условия с оператором ИЛИ. И именно так планировщик СУБД оптимизирует выполнение такого условия. Он формирует выборку из одной таблицы отдельно по каждому из условий вокруг ИЛИ. Согласитесь что планировщик Postgres ведет себя достаточно умно в этом случае?
Откуда взялся оператор ИЛИ, мы разберем в следующей части расследования, а сейчас сосредоточимся на анализе самой проблемы.

Рис. План проблемного запроса — свойства проблемного оператора получения данных
На плане запроса обращаем внимание на самый большой красный круг. Такое явное выделение указывает на наличие проблемы при выполнении запроса. Эта часть плана запроса находится в области выборки данных из регистра накопления. Ее мы и будем рассматривать в дальнейшем.
Если мы наведем мышку на этот оператор, то во всплывающем окне появится расшифровка. Давайте посмотрим на нее подробнее. И мы видим, что данные выбираются через индекс регистра накопления «Запасы и потребности», однако эта операция выполняется очень долго. И это неудивительно: в процессе отбирается всего 4 записи, но для этого впустую перебирается почти 2.5 млн строк. На это прямо указывает значение Rows Removed by Filter (RRBF) — количество строк, отброшенных фильтром после сканирования.
Согласитесь, это крайне неоптимальное использование индекса. Планировщик запросов в данном случае явно ошибается. Объясним, почему:
- Неселективный отбор по индексу: Условие в индексе включает общий реквизит и тип.
- Все записи имеют единственное значение общего реквизита — 0. Это поле практически бесполезно для отбора.
- Различных типов не так много, а записей по ним — огромное количество. Без отбора по значению ссылки индекс захватывает слишком широкий диапазон данных.
- Ключевое условие — в фильтре: Отбор по самому значению ссылки находится не в условиях доступа к индексу где должно находиться, а в фильтре (Filter). Это означает, что сначала будут отсканированы все записи, подходящие под нестрогий индекс (общий реквизит=0 и тип=X), а уже потом к этим миллионам записей будет применено условие по ссылке.
- Избыточное условие: В фильтре присутствует условие OR для типа, которое уже частично учтено при поиске по индексу, но это не критично.
Вывод: Индекс используется максимально эффективно, когда в условии отбора задействованы все его ключевые поля. Чем меньше полей используется, тем хуже селективность. В нашем случае ситуация усугубляется тем, что первое поле индекса (область основных данных) имеет нулевую селективность, а второе (тип) — слишком низкую. В результате в выборку попадают миллионы записей, и только затем применяется узкое условие по ссылке, которое, к сожалению, не является частью фильтра по индексу.
Вернёмся к плану запроса. Теперь посмотрим, как выполняется получение данных из второго объединения.

Рис. План выполнения запроса для второго объединения данных
В данном случае мы наблюдаем картину, кардинально отличающуюся от предыдущего случая: выбирается небольшой объём данных, а условие по индексу отрабатывает эффективно. Это объясняется тем, что в условии поиска по индексу задействованы сразу три поля отбора, благодаря чему планировщик сразу обращается к узкому диапазону записей. В фильтре остаётся лишь одно дополнительное условие — проверка активности, — которое применяется к уже сильно сокращённому результату.
Мы можем предположить, что выбор данных из источника #6 должен был быть только по одному типу, а из второго источника #9 только по другому типу. В действительности же мы видим, что в условие получения данных (проблемный) кружок планировщик зачем-то добавил отбор и по второму типу. Это явная его ошибка, которая и приводит к проблемам.
3.3 Детальный разбор проблемы
Мы поняли что проблема вызвана наличием оператора ИЛИ. Теперь давайте разберемся, откуда в SQL-запросе взялось условие с этим оператором, ведь в исходном запросе на 1С его не было.
Вернемся к тексту SQL-запроса и внимательно изучим условие отбора в секции WHERE.

Рис. Фрагмент SQL-запроса с условием в секции WHERE
Мы видим что оператор ИЛИ делит условие на две похожие части. В первой ставится отбор по некоторому типу ссылки и условие на вхождение набора ссылок в поле ссылка. Вторая часть - это отбор по другому типу ссылок и их значениям. Почему же получилось такое разделение?
Синтаксис оператора «В» в 1С и SQL может быть представлен в двух основных вариантах:
- Проверка вхождения в набор значений: Выражение В (Значение1, Значение2, ...)
- Проверка вхождения в результат подзапроса: Выражение В (Выбрать из подзапроса)
Теперь ключевой момент: посмотрим, как представлено составное поле «Регистратор» на уровне СУБД. Его структура показана на рисунке ниже.

Рис. Схема представления поля "Регистратор" в 1С и СУБД
В то время как на уровне 1С это одна колонка, на уровне СУБД она физически разбивается на два поля:
- RecorderTRef — хранит идентификатор типа документа (ссылку на метаданные).
- RecorderRRef — хранит непосредственно уникальный идентификатор (GUID) самого документа-регистратора.
Для ERP примерное представление регистра накопления будет выглядеть чуть иначе.

Рис. Схема таблицы регистра накопления на уровнях 1С и СУБД (не показаны поля измерений, ресурсов и реквизитов)
Первый вариант использования оператора «В» позволяет выполнять проверку только по одномерному массиву, и в исходном 1С запросе это именно так и выглядит.

Однако когда мы переходим на уровень СУБД, ситуация меняется. Наш одномерный массив ссылок на уровне базы данных становится двумерным, так как каждая ссылка представлена двумя полями: RecorderTRef (тип) и RecorderRRef (идентификатор). Невозможно напрямую записать условие В для такой составной структуры.
Чтобы сохранить ту же логику, платформа 1С вынуждена преобразовать исходное условие. Вместо простого оператора В генерируется эквивалентная конструкция, представляющая собой набор условий, объединенных через «ИЛИ»:

Вот почему появляется оператор ИЛИ (OR). Такое преобразование приводит к созданию громоздкого условия ИЛИ. Планировщику запросов СУБД зачастую сложно эффективно построить план для таких конструкций, особенно когда список значений велик, что мы и наблюдаем в виде медленного выполнения.
Важное замечание!
Может возникнуть предположение, что условие по типу (RecorderTRef) можно было бы не использовать, сравнивая только по GUID (RecorderRRef). Однако это привело бы к некорректной работе запроса.
Почему это опасно: Если в разных типах объектов окажутся одинаковые GUID, запрос вернет лишние или неверные записи. Такая ситуация — не гипотетическая. Она регулярно возникает, например, при выполнении обменов данными.
Реальный пример из практики: При выгрузке документа «Реализация товаров и услуг» из конфигурации ERP в «Бухгалтерию» один исходный документ может разделяться на два в системе-приемнике (например, при использовании механизма «товаров в пути»). Самым удобным техническим решением в этом случае часто является сохранение одного и того же GUID для обоих создаваемых документов.
Таким образом, проверка и по типу, и по ссылке является строго обязательной для гарантии корректности результатов, а возникающие из-за этого проблемы производительности необходимо решать другими способами.
Варианты решения
Вариант 1. Замена условия «ИЛИ» на оператор «Объединение»
Одно из самых очевидных решений — это изменить исходный запрос, заменив условие ИЛИ на оператор ОБЪЕДИНЕНИЕ.
Идея заключается в том, чтобы разбить один сложный запрос с условием ИЛИ на несколько отдельных запросов, результаты которых затем объединяются.
В нашем примере использовалось два типа ссылок. Давайте разберем его реализацию.
ВЫБРАТЬ РАЗЛИЧНЫЕ
Товары.Номенклатура КАК Номенклатура,
Товары.Характеристика КАК Характеристика,
Товары.Ссылка.Склад КАК Склад,
Товары.Назначение КАК Назначение,
Товары.ДокументОтгрузки КАК Заказ,
Товары.Ссылка.Дата КАК ДатаСобытия
ПОМЕСТИТЬ ДвиженияПриЗаписи
ИЗ
Документ.ПриходныйОрдерНаТовары.Товары КАК Товары
ГДЕ
Товары.Ссылка = &Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
Товары.Номенклатура КАК Номенклатура,
Товары.Характеристика КАК Характеристика,
Товары.Склад КАК Склад,
Товары.Назначение КАК Назначение,
Товары.Заказ КАК Заказ,
Товары.ДатаСобытия КАК ДатаСобытия
ИЗ
ДвиженияПриЗаписи КАК Товары
ОБЪЕДИНИТЬ
ВЫБРАТЬ РАЗЛИЧНЫЕ
Движения.Номенклатура,
Движения.Характеристика,
Движения.Склад,
Движения.Назначение,
Движения.Заказ,
Движения.ДатаСобытия
ИЗ
РегистрНакопления.ЗапасыИПотребности КАК Движения
ГДЕ
Движения.Регистратор В(&РегистраторыТип1)
И Движения.Активность
ОБЪЕДИНИТЬ
ВЫБРАТЬ РАЗЛИЧНЫЕ
Движения.Номенклатура,
Движения.Характеристика,
Движения.Склад,
Движения.Назначение,
Движения.Заказ,
Движения.ДатаСобытия
ИЗ
РегистрНакопления.ЗапасыИПотребности КАК Движения
ГДЕ
Движения.Регистратор В(&РегистраторыТип2)
И Движения.Активность
После выполнения запроса, использующего UNION, мы получаем следующий план:

Рис. План запроса - Вариант 1
Запрос стал выполняться очень быстро, что подтверждает эффективность данной оптимизации — время выполнения составляет менее 1 мс.
https://explain.tensor.ru/archive/explain/4575fc70a5e9c43f34e5fe1f5ca966b4:0:2024-04-03#visio
Однако у этого метода есть существенные недостатки:
Нам необходимо заранее разделить входной массив параметров по типам ссылок и для каждой группы сформировать отдельную часть запроса в конструкции UNION. Это можно делать как статически (если типы известны заранее), так и динамически, собирая запрос в коде.
В результате такое решение становится громоздким и сложным для поддержки, особенно если список типов может меняться.
Вариант 2. Использование оператора «В» с подзапросом
Исправим ситуацию, воспользовавшись вторым вариантом синтаксиса оператора «В» — с подзапросом.
Перепишем исходный запрос следующим образом:
ВЫБРАТЬ
Т.Регистратор КАК Регистратор
ПОМЕСТИТЬ ВтРегистраторы
ИЗ
&ВтТЗ КАК Т
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
Товары.Номенклатура КАК Номенклатура,
Товары.Характеристика КАК Характеристика,
Товары.Ссылка.Склад КАК Склад,
Товары.Назначение КАК Назначение,
Товары.ДокументОтгрузки КАК Заказ,
Товары.Ссылка.Дата КАК ДатаСобытия
ПОМЕСТИТЬ ДвиженияПриЗаписи
ИЗ
Документ.ПриходныйОрдерНаТовары.Товары КАК Товары
ГДЕ
Товары.Ссылка = &ССылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
Товары.Номенклатура КАК Номенклатура,
Товары.Характеристика КАК Характеристика,
Товары.Склад КАК Склад,
Товары.Назначение КАК Назначение,
Товары.Заказ КАК Заказ,
Товары.ДатаСобытия КАК ДатаСобытия
ИЗ
ДвиженияПриЗаписи КАК Товары
ОБЪЕДИНИТЬ
ВЫБРАТЬ РАЗЛИЧНЫЕ
Движения.Номенклатура,
Движения.Характеристика,
Движения.Склад,
Движения.Назначение,
Движения.Заказ,
Движения.ДатаСобытия
ИЗ
РегистрНакопления.ЗапасыИПотребности КАК Движения
ГДЕ
Движения.Регистратор В
(ВЫБРАТЬ
Вт.Регистратор
ИЗ
ВтРегистраторы КАК Вт)
И Движения.Активность
При использовании этого варианта запрос также выполняется очень быстро. Время выполнения составляет менее 1 мс.

Рис. План запроса - вариант 2
https://explain.tensor.ru/archive/explain/b3c210c856f6961269b6519860fe4108:0:2024-04-03#visio
Оценка решения:
Преимущество: В отличие от первого варианта, здесь отсутствует громоздкая конструкция запроса с множеством UNION. Текст запроса остается простым и читаемым.
Недостаток: Требуется создание дополнительной временной таблицы для размещения регистраторов. Однако, поскольку объем этих данных обычно невелик, операция выполняется достаточно быстро и не оказывает значительного влияния на общую производительность.
Реализация исправления
Для устранения проблемы был выбран Вариант 2, так как он обеспечивает высокую производительность и технически реализуется проще, чем разбиение запроса на UNION.
Контекст: Учитывая, что пользователи испытывают сложности в работе, а конфигурация находится на поддержке, исправление будет внедрено с помощью механизма расширений для минимального вмешательства в основную конфигурацию.
План действий:
- В Конфигураторе находим объект «РегистрНакопления.ЗапасыИПотребности».
- В его модуле менеджера находим функцию УстановитьБлокировкиЗаказов().
- С помощью механизма расширений добавляем эту функцию в список объектов для контроля и изменения (Вариант контроля: «Вызов исключения», Вариант изменения: «Замена»).
- В коде функции находим участок, где формируется параметр «Регистраторы» (массив значений, передаваемый в запрос).
- Ключевое изменение: Заменяем передачу простого массива на передачу таблицы значений, которая будет использоваться в подзапросе.
Функция УстановитьБлокировкиЗаказовИТоваров(НаборЗаписей, Ссылка, ЭтоОбновлениеИБ)
//...
//...
БлокировкаДанных.Заблокировать();
#Удаление
Регистраторы = Регистраторы.Выгрузить().ВыгрузитьКолонку("Регистратор");
Регистраторы.Добавить(Ссылка);
#КонецУдаления
#Вставка
Регистраторы = Регистраторы.Выгрузить();
стр_н = Регистраторы.Добавить();
стр_н.Регистратор = Ссылка;
#КонецВставки
Запрос.УстановитьПараметр("Регистраторы", Регистраторы);
Запрос.УстановитьПараметр("ТаблицаТовары", НаборЗаписей.Выгрузить());
//...
//...
Замечание!
В коде выше достаточно плохо выглядит решение о переиспользовании переменной «Регистраторы» со сменой типа. Более правильно выглядит введение новой переменной.
И нам осталось еще в самом запросе добавить создание временной таблицы и изменить условие на новое (блоки удаления и вставки):
//....
Запрос.Текст =
#Вставка
"ВЫБРАТЬ
| ТЗ.Регистратор КАК Регистратор
|ПОМЕСТИТЬ ВтРегистраторы
|ИЗ
| &Регистраторы как ТЗ
|;
|"+
#КонецВставки
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Характеристика КАК Характеристика,
| Товары.Склад КАК Склад,
| Товары.Назначение КАК Назначение,
//....
//....
| Движения.ДатаСобытия КАК ДатаСобытия
|ИЗ
| РегистрНакопления.ЗапасыИПотребности КАК Движения
|ГДЕ
#Удаление
| Движения.Регистратор В (&Регистраторы)
#КонецУдаления
#Вставка
| Движения.Регистратор В (ВЫБРАТЬ Вт.Регистратор ИЗ ВтРегистраторы КАК Вт)
#КонецВставки
| И Движения.Активность";
Товары = Запрос.Выполнить();
//....
//....
Возврат Результат;
КонецФункции
Вот и всё! В результате проведённого анализа и выполненных изменений проблема решена. Все исправления реализованы в расширении, которое готово к сохранению.
После согласования с заказчиком мы применим это расширение на обслуживаемой базе, что позволит устранить блокировки и значительно повысить производительность работы пользователей.
Заключение
Давайте оценим эффективность проведённой оптимизации. Разделив исходное время выполнения (10 000 мс) на новое (0.3 мс), мы получаем впечатляющий результат:
10 000 мс / 0.3 мс ≈ 33 333 раза.
В результате блокировки, которые мешали выполнять свои обязанности сотрудникам полностью исчезли. Нормальная работа в системе была восстановлена.
Данный пример иллюстрирует, что в высоконагруженных базах могут неожиданно проявляться проблемы, вызванные, казалось бы, незначительными особенностями генерации запросов. Умение оперативно находить и исправлять такие проблемы — ключевой навык для обеспечения стабильности и производительности сервиса. Важно подчеркнуть, что подобные узкие места часто проявляются только на базах с большим объемом данных, поэтому при разработке и тестировании необходимо использовать базы, релевантные по наполненности боевым.
Итоги проведенной работы:
- Проблема решена: Блокировки устранены. Запрос выполняется практически мгновенно, что полностью исключило его негативное влияние на других пользователей.
- Освоен метод диагностики: Мы рассмотрели практический метод оперативного поиска и анализа причин блокировок в системе 1С.
- Выявлена ключевая особенность платформы: Мы познакомились с тем, как платформа 1С транслирует оператор «В» для составных типов на уровень SQL, преобразуя его в условие ИЛИ, которое в ряде случаев оказывается крайне неоптимальным для планировщика СУБД. Понимание этого механизма позволяет заранее проектировать запросы, избегая подобных проблем.
Вступайте в нашу телеграмм-группу Инфостарт