Как найти и оптимизировать медленный запрос в 1С, вызывающий зависания интерфейса?

Программист 1С v8.3 (Управляемые формы) 1С:Документооборот
← На главную

Часто в работе с информационными системами 1С мы сталкиваемся с ситуациями, когда интерфейс начинает хаотически зависать, замедляя работу пользователей. Типичный сценарий: действия с задачами в документообороте, такие как согласование или отклонение, приводят к блокировке UI на продолжительное время – до 120 секунд. Такие проблемы могут проявляться нерегулярно: можно успешно обработать множество задач, а затем подряд несколько операций вызовут зависание. В консоли кластера мы видим, что проблемные пользователи оказываются в топе по времени вызовов СУБД, что недвусмысленно указывает на наличие «плохого» запроса. Давайте разберем, как эффективно выявить такой запрос и какие шаги предпринять для его оптимизации, используя доступные в 1С и СУБД инструменты.

1. Первоначальная диагностика и выявление узких мест

Прежде чем приступать к глубокому анализу, важно собрать первичные данные и локализовать проблему. Если мы видим, что пользователи находятся в топе по времени вызовов СУБД, это уже серьезный сигнал.

  1. Консоль кластера и мониторинг активных сеансов: Регулярно отслеживайте активные сеансы в консоли кластера 1С. Обращайте внимание на пользователей, у которых наблюдаются длительные операции с базой данных. Это поможет сузить круг поиска до конкретных пользователей и временных интервалов.
  2. Хаотичность и время зависания: Заметьте, что проблема проявляется хаотически, но с конкретным временем зависания – до 120 секунд. Это может указывать на превышение таймаута на уровне 1С или СУБД, а также на длительное ожидание блокировок.
  3. Использование APDEX: В качестве метрики для оценки производительности пользовательского опыта мы можем рассмотреть использование APDEX (Application Performance Index). Этот индекс помогает комплексно оценить удовлетворенность пользователей производительностью системы, выявляя операции, которые не укладываются в установленные нормативы времени.

2. Настройка и анализ Технологического журнала (ТЖ)

Технологический журнал (ТЖ) является нашим основным инструментом для детального сбора информации о работе платформы 1С и взаимодействии с СУБД. Он позволяет фиксировать различные события, связанные с выполнением запросов, блокировками и вызовами методов.

  1. Выбор событий для ТЖ: Для поиска медленных запросов и проблем с блокировками мы рекомендуем включать следующие события:
    • DBMSSQL (для MS SQL Server): Собирает информацию о выполнении SQL-запросов к базе данных, включая текст запроса, время выполнения и количество прочитанных строк. Для других СУБД аналогичные события, например DBPOSTGRS для PostgreSQL.
    • CALL: Записывает вызовы методов платформы, что позволяет понять, какие именно действия пользователя приводят к выполнению дорогих операций.
    • PLAN (если доступно): Фиксирует планы выполнения запросов, что критически важно для анализа их эффективности.
    • SDBL: Охватывает общие операции с базой данных.
    • TDEADLOCK: Регистрирует события взаимоблокировок, что помогает выявить, когда два или более сеанса блокируют друг друга.
    • Особое внимание уделите событиям SQL для анализа текста запросов, времени их выполнения и количества прочитанных строк.
  2. Фильтрация и настройка критических параметров ТЖ: Для того чтобы не перегружать ТЖ избыточной информацией, мы должны настроить фильтры.
    • По длительности: Установите фильтр на период, например, по длительности выполнения запроса более 5 секунд (Duration > 5000000 микросекунд). Это позволит сосредоточиться на действительно медленных операциях.
    • По пользователю: Если мы уже сузили круг поиска до конкретных проблемных пользователей, можно добавить фильтр по имени пользователя или его идентификатору.
    • По периоду времени: Если проблема произошла в определенный интервал (например, с 12:03 до 12:06), мы можем собрать данные за чуть больший период, например, с 12:00 до 12:15. Это гарантирует, что начало и конец очень долгого запроса попадут в отбор.
    • Общие критические настройки: Используйте рекомендации 1С по настройке ТЖ для критических ситуаций, которые обеспечивают достаточный уровень детализации для диагностики производительности.
  3. Анализ данных ТЖ: После сбора данных ТЖ мы можем использовать специализированные обработки или внешние инструменты (например, "Парсер ТЖ") для анализа логов. Эти инструменты помогут нам визуализировать информацию, выявить самые долгие запросы, определить места возникновения блокировок и проанализировать их причины. Сообщение 7, где автор нашел конкретный запрос, явно демонстрирует эффективность такого подхода.

3. Анализ найденного запроса и его оптимизация

В нашем случае, проблемный запрос был найден в модуле формы с задачами пользователя и отвечает за обновление дерева задач. Рассмотрим его структуру и возможные пути оптимизации.


ВЫБРАТЬ ИсполнителиРолейИДелегаты.РольПользователь КАК Исполнитель, МИНИМУМ(ИсполнителиРолейИДелегаты.НастройкаДелегирования) КАК НастройкаДелегирования
ПОМЕСТИТЬ ИсполнителиЗадач
ИЗ РегистрСведений.ИсполнителиРолейИДелегаты КАК ИсполнителиРолейИДелегаты
ГДЕ ИсполнителиРолейИДелегаты.ИсполнительДелегат = &ТекущийПользователь
И ИсполнителиРолейИДелегаты.ИмяОбластиДелегирования В ("", "ПроцессыИЗадачи")
СГРУППИРОВАТЬ ПО ИсполнителиРолейИДелегаты.РольПользователь
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ЗадачаИсполнителя.Ссылка КАК Ссылка, ЗадачаИсполнителя.Дата КАК Дата, ЗадачаИсполнителя.Наименование КАК Наименование, ЗадачаИсполнителя.СрокИсполнения КАК СрокИсполнения, ЗадачаИсполнителя.ПринятаКИсполнению КАК ПринятаКИсполнению, ЗадачаИсполнителя.Выполнена КАК Выполнена, ЗадачаИсполнителя.Автор КАК Автор, ЗадачаИсполнителя.БизнесПроцесс КАК БизнесПроцесс, ЗадачаИсполнителя.ТочкаМаршрута КАК ТочкаМаршрута, ЗадачаИсполнителя.ПредметСтрокой КАК ПредметСтрокой, ЗадачаИсполнителя.Проект КАК Проект, ЗадачаИсполнителя.Исполнитель КАК Исполнитель, ЗадачаИсполнителя.ТекущийИсполнитель КАК ТекущийИсполнитель, ИсполнителиЗадач.НастройкаДелегирования КАК НастройкаДелегирования, ЗадачаИсполнителя.Важность КАК Важность, ЗадачиДляВыполнения.СостояниеВыполнения КАК СостояниеВыполнения
ПОМЕСТИТЬ Задачи
ИЗ Задача.ЗадачаИсполнителя КАК ЗадачаИсполнителя
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсполнителиЗадач КАК ИсполнителиЗадач
ПО ЗадачаИсполнителя.ТекущийИсполнитель = ИсполнителиЗадач.Исполнитель
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗадачиДляВыполнения КАК ЗадачиДляВыполнения
ПО ЗадачаИсполнителя.Ссылка = ЗадачиДляВыполнения.Задача
ГДЕ ЗадачаИсполнителя.СостояниеБизнесПроцесса = ЗНАЧЕНИЕ(Перечисление.СостоянияБизнесПроцессов.Активен)
И ЕСТЬNULL(ЗадачиДляВыполнения.СостояниеВыполнения, НЕОПРЕДЕЛЕНО) <> ЗНАЧЕНИЕ(Перечисление.СостоянияЗадачДляВыполнения.ГотоваКВыполнению)
И ЗадачаИсполнителя.ПометкаУдаления = ЛОЖЬ
И ЗадачаИсполнителя.ИсключенаИзПроцесса = ЛОЖЬ
И ЗадачаИсполнителя.Выполнена = ЛОЖЬ
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ Задачи.Ссылка КАК Ссылка, Задачи.Дата КАК Дата, Задачи.Наименование КАК Наименование, Задачи.СрокИсполнения КАК СрокИсполнения, Задачи.ПринятаКИсполнению КАК ПринятаКИсполнению, Задачи.Выполнена КАК Выполнена, Задачи.Автор КАК Автор, Задачи.БизнесПроцесс КАК БизнесПроцесс, Задачи.ТочкаМаршрута КАК ТочкаМаршрута, Задачи.ПредметСтрокой КАК ПредметСтрокой, Задачи.Проект КАК Проект, Задачи.Исполнитель КАК Исполнитель, Задачи.ТекущийИсполнитель КАК ТекущийИсполнитель, Задачи.Важность КАК Важность, Задачи.СостояниеВыполнения КАК СостояниеВыполнения, Задачи.НастройкаДелегирования КАК НастройкаДелегирования
ПОМЕСТИТЬ ЗадачиСRLS
ИЗ Задачи КАК Задачи
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.УчастникиПроцессов КАК УчастникиПроцессов
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставСубъектовПравДоступа КАК СоставСубъектовПравДоступа
ПО УчастникиПроцессов.Участник = СоставСубъектовПравДоступа.Субъект
ПО Задачи.БизнесПроцесс = УчастникиПроцессов.Процесс
ГДЕ СоставСубъектовПравДоступа.Пользователь = &ТекущийПользователь
И СоставСубъектовПравДоступа.ИмяОбластиДелегирования В ("", "ПроцессыИЗадачи")
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ЗадачаИсполнителя.Ссылка КАК Ссылка, ЗадачаИсполнителя.БизнесПроцесс КАК БизнесПроцесс, ДанныеБизнесПроцессов.ГлавнаяЗадача КАК ГлавнаяЗадача
ПОМЕСТИТЬ ЗадачиАвтора
ИЗ Задача.ЗадачаИсполнителя КАК ЗадачаИсполнителя
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсполнителиЗадач КАК ИсполнителиЗадач
ПО ЗадачаИсполнителя.Автор = ИсполнителиЗадач.Исполнитель
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗадачиДляВыполнения КАК ЗадачиДляВыполнения
ПО ЗадачаИсполнителя.Ссылка = ЗадачиДляВыполнения.Задача
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеБизнесПроцессов КАК ДанныеБизнесПроцессов
ПО ЗадачаИсполнителя.БизнесПроцесс = ДанныеБизнесПроцессов.БизнесПроцесс
ГДЕ ЗадачаИсполнителя.СостояниеБизнесПроцесса = ЗНАЧЕНИЕ(Перечисление.СостоянияБизнесПроцессов.Активен)
И ЕСТЬNULL(ЗадачиДляВыполнения.СостояниеВыполнения, НЕОПРЕДЕЛЕНО) <> ЗНАЧЕНИЕ(Перечисление.СостоянияЗадачДляВыполнения.ГотоваКВыполнению)
И ЗадачаИсполнителя.ПометкаУдаления = ЛОЖЬ
И ЗадачаИсполнителя.ИсключенаИзПроцесса = ЛОЖЬ
И ЗадачаИсполнителя.Выполнена = ЛОЖЬ
И НЕ ЗадачаИсполнителя.Исполнитель В (ВЫБРАТЬ ИсполнителиЗадач.Исполнитель ИЗ ИсполнителиЗадач КАК ИсполнителиЗадач)
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ИСТИНА КАК ЕстьПодчиненныеЗадачи, ЗадачиАвтора.ГлавнаяЗадача КАК ГлавнаяЗадача
ПОМЕСТИТЬ ВТ_ПодчиненныеЗадачи
ИЗ ЗадачиАвтора КАК ЗадачиАвтора
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Задачи КАК Задачи
ПО ЗадачиАвтора.ГлавнаяЗадача = Задачи.Ссылка
СГРУППИРОВАТЬ ПО ЗадачиАвтора.ГлавнаяЗадача
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ЗадачаИсполнителяПредметы.Ссылка КАК Ссылка, ЗадачаИсполнителяПредметы.НомерСтроки КАК НомерСтроки, ЗадачаИсполнителяПредметы.РольПредмета КАК РольПредмета, ЗадачаИсполнителяПредметы.ИмяПредмета КАК ИмяПредмета, ЗадачаИсполнителяПредметы.Предмет КАК Предмет, ЗадачаИсполнителяПредметы.ДоступноУдаление КАК ДоступноУдаление, ЗадачаИсполнителяПредметы.ОбязательноеЗаполнение КАК ОбязательноеЗаполнение
ПОМЕСТИТЬ ВТ_ПредметыПоЗадачам
ИЗ Задача.ЗадачаИсполнителя.Предметы КАК ЗадачаИсполнителяПредметы
ГДЕ ЗадачаИсполнителяПредметы.Ссылка В (ВЫБРАТЬ ЗадачиСRLS.Ссылка ИЗ ЗадачиСRLS КАК ЗадачиСRLS)
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ВТ_ПредметыПоЗадачам.НомерСтроки КАК НомерСтроки, ВТ_ПредметыПоЗадачам.Предмет КАК Предмет, ВТ_ПредметыПоЗадачам.Ссылка КАК Задача
ПОМЕСТИТЬ ВТ_ПредметыВнтуренниеДокументы
ИЗ ВТ_ПредметыПоЗадачам КАК ВТ_ПредметыПоЗадачам
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ВнутренниеДокументы КАК ВнутренниеДокументы
ПО (ВТ_ПредметыПоЗадачам.Предмет ССЫЛКА Справочник.ВнутренниеДокументы)
И ВТ_ПредметыПоЗадачам.Предмет = ВнутренниеДокументы.Ссылка
ГДЕ НЕ ВнутренниеДокументы.Ссылка ЕСТЬ NULL
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ МИНИМУМ(ВТ_ПредметыВнтуренниеДокументы.НомерСтроки) КАК НомерСтроки, ВТ_ПредметыВнтуренниеДокументы.Задача КАК Задача
ПОМЕСТИТЬ ВТ_НомерПредмета
ИЗ ВТ_ПредметыВнтуренниеДокументы КАК ВТ_ПредметыВнтуренниеДокументы
СГРУППИРОВАТЬ ПО ВТ_ПредметыВнтуренниеДокументы.Задача
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ ЗадачиСRLS.Ссылка КАК Задача, ВложенныйЗапрос.Предмет КАК Предмет
ПОМЕСТИТЬ ВТ_Предмет
ИЗ ЗадачиСRLS КАК ЗадачиСRLS
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ВТ_ПредметыПоЗадачам.Ссылка КАК Задача, ВТ_ПредметыПоЗадачам.Предмет КАК Предмет
ИЗ ВТ_ПредметыПоЗадачам КАК ВТ_ПредметыПоЗадачам
ГДЕ (ВТ_ПредметыПоЗадачам.НомерСтроки, ВТ_ПредметыПоЗадачам.Ссылка) В (ВЫБРАТЬ ВТ_НомерПредмета.НомерСтроки, ВТ_НомерПредмета.Задача ИЗ ВТ_НомерПредмета КАК ВТ_НомерПредмета)) КАК ВложенныйЗапрос
ПО ЗадачиСRLS.Ссылка = ВложенныйЗапрос.Задача
ГДЕ НЕ ВложенныйЗапрос.Предмет ЕСТЬ NULL
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ ЗадачиСRLS.Ссылка КАК Ссылка, ЗадачиСRLS.Дата КАК Дата, ЗадачиСRLS.Наименование КАК Наименование, ЗадачиСRLS.СрокИсполнения КАК СрокИсполнения, ЗадачиСRLS.ПринятаКИсполнению КАК ПринятаКИсполнению, ЗадачиСRLS.Выполнена КАК Выполнена, ЗадачиСRLS.Автор КАК Автор, ЗадачиСRLS.БизнесПроцесс КАК БизнесПроцесс, ЗадачиСRLS.ТочкаМаршрута КАК ТочкаМаршрута, ЗадачиСRLS.ПредметСтрокой КАК ПредметСтрокой, ЗадачиСRLS.Проект КАК Проект, ЗадачиСRLS.ТекущийИсполнитель КАК ТекущийИсполнитель,
ВЫБОР
КОГДА ЗадачиСRLS.Проект = ЗНАЧЕНИЕ(Справочник.Проекты.ПустаяСсылка) ТОГДА &ИмяГруппыБезПроекта
ИНАЧЕ ЗадачиСRLS.Проект.Представление
КОНЕЦ КАК ПредставлениеПроекта,
ЗадачиСRLS.Исполнитель КАК Исполнитель,
ИСТИНА КАК Показывать,
ВЫБОР
КОГДА ЗадачиСRLS.СрокИсполнения = ДАТАВРЕМЯ(1, 1, 1) ТОГДА ЛОЖЬ
КОГДА &ИспользоватьДатуИВремяВСрокахЗадач = ИСТИНА ТОГДА ЗадачиСRLS.СрокИсполнения <= &ТекущаяДата
ИНАЧЕ ЗадачиСRLS.СрокИсполнения < &ДатаОкончанияТекущегоДня
КОНЕЦ КАК Просрочена,
ВЫБОР
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ИСТИНА И ЗадачиСRLS.СрокИсполнения <> ДАТАВРЕМЯ(1, 1, 1) И ЗадачиСRLS.СрокИсполнения < &ДатаОкончанияТекущегоДня ТОГДА 0
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ИСТИНА И ЗадачиСRLS.СрокИсполнения = ДАТАВРЕМЯ(1, 1, 1) ТОГДА 1
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ИСТИНА И &ИспользоватьДатуИВремяВСрокахЗадач = ИСТИНА И ЗадачиСRLS.СрокИсполнения = &ТекущаяДата ТОГДА 1
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ИСТИНА И ЗадачиСRLS.СрокИсполнения >= &ТекущаяДата ТОГДА 2
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ЛОЖЬ И ЗадачиСRLS.СрокИсполнения <> ДАТАВРЕМЯ(1, 1, 1) И ЗадачиСRLS.СрокИсполнения < &ДатаОкончанияТекущегоДня ТОГДА 3
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ЛОЖЬ И ЗадачиСRLS.СрокИсполнения = ДАТАВРЕМЯ(1, 1, 1) ТОГДА 4
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ЛОЖЬ И &ИспользоватьДатуИВремяВСрокахЗадач = ИСТИНА И ЗадачиСRLS.СрокИсполнения = &ТекущаяДата ТОГДА 4
КОГДА ЗадачиСRLS.ПринятаКИсполнению = ЛОЖЬ И ЗадачиСRLS.СрокИсполнения >= &ТекущаяДата ТОГДА 5
КОНЕЦ КАК Приоритет,
ЕСТЬNULL(ФлагиОбъектов.Пометка, ЛОЖЬ) КАК ПомеченоНаУдаление,
ЕСТЬNULL(ВТ_ПодчиненныеЗадачи.ЕстьПодчиненныеЗадачи, ЛОЖЬ) КАК ЕстьПодчиненныеЗадачи,
ВЫБОР
КОГДА КешИнформацииОбОбъектах.СостояниеКонтроля = ЗНАЧЕНИЕ(Перечисление.СостоянияКонтроля.НаКонтроле) ТОГДА 1
КОГДА КешИнформацииОбОбъектах.СостояниеКонтроля = ЗНАЧЕНИЕ(Перечисление.СостоянияКонтроля.НаКонтролеНесколько)
ИЛИ КешИнформацииОбОбъектах.СостояниеКонтроля = ЗНАЧЕНИЕ(Перечисление.СостоянияКонтроля.СмешанноНесколько) ТОГДА
ВЫБОР КОГДА КешИнформацииОбОбъектах.СрокИсполнения = ДАТАВРЕМЯ(1, 1, 1) ИЛИ КешИнформацииОбОбъектах.СрокИсполнения >= &ТекущаяДата ТОГДА 2
КОГДА КешИнформацииОбОбъектах.СрокИсполненияОбщий = ДАТАВРЕМЯ(1, 1, 1) ИЛИ КешИнформацииОбОбъектах.СрокИсполненияОбщий >= &ТекущаяДата ТОГДА 3
ИНАЧЕ 2
КОНЕЦ
КОГДА КешИнформацииОбОбъектах.СостояниеКонтроля = ЗНАЧЕНИЕ(Перечисление.СостоянияКонтроля.СнятСКонтроля) ТОГДА 4
КОГДА КешИнформацииОбОбъектах.СостояниеКонтроля = ЗНАЧЕНИЕ(Перечисление.СостоянияКонтроля.СнятСКонтроляНесколько) ТОГДА 4
КОГДА КешИнформацииОбОбъектах.СостояниеКонтроля = ЗНАЧЕНИЕ(Перечисление.СостоянияКонтроля.СмешанноНесколько) ТОГДА 2
ИНАЧЕ 0
КОНЕЦ КАК СостояниеКонтроля,
ДанныеБизнесПроцессов.ГлавнаяЗадача КАК ГлавнаяЗадача,
ЗадачиСRLS.СостояниеВыполнения = ЗНАЧЕНИЕ(Перечисление.СостоянияЗадачДляВыполнения.ВыполнениеОтменено) КАК ОшибкаПриВыполненииЗадачи,
ЗадачиСRLS.СостояниеВыполнения КАК СостояниеВыполнения,
ВТ_Предмет.Предмет.ВидДокумента КАК ВидДокумента,
ВТ_Предмет.Предмет.Организация КАК Организация,
ВТ_Предмет.Предмет.Контрагент КАК Контрагент,
ВТ_Предмет.Предмет.Подразделение КАК Подразделение,
ВТ_Предмет.Предмет.Сумма КАК Сумма,
ВТ_Предмет.Предмет.Валюта КАК Валюта,
ЕСТЬNULL(ВТ_Предмет.Предмет.СрокИсполнения, ДАТАВРЕМЯ(1, 1, 1)) КАК СрокИсполненияДокумента,
ЕСТЬNULL(ВТ_Предмет.Предмет.ДатаСоздания, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаСозданияДокумента
ИЗ ЗадачиСRLS КАК ЗадачиСRLS
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФлагиОбъектов КАК ФлагиОбъектов
ПО ЗадачиСRLS.Ссылка = ФлагиОбъектов.Объект
И (ФлагиОбъектов.Пользователь = &ТекущийПользователь)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КешИнформацииОбОбъектах КАК КешИнформацииОбОбъектах
ПО ЗадачиСRLS.Ссылка = КешИнформацииОбОбъектах.Объект
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеБизнесПроцессов КАК ДанныеБизнесПроцессов
ПО ЗадачиСRLS.БизнесПроцесс = ДанныеБизнесПроцессов.БизнесПроцесс
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Предмет КАК ВТ_Предмет
ПО ЗадачиСRLS.Ссылка = ВТ_Предмет.Задача
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПодчиненныеЗадачи КАК ВТ_ПодчиненныеЗадачи
ПО ЗадачиСRLS.Ссылка = ВТ_ПодчиненныеЗадачи.ГлавнаяЗадача
ГДЕ (НЕ ЕСТЬNULL(ВТ_ПодчиненныеЗадачи.ЕстьПодчиненныеЗадачи, ЛОЖЬ)
И ВЫБОР КОГДА ДанныеБизнесПроцессов.ГлавнаяЗадача <> ЗНАЧЕНИЕ(Задача.ЗадачаИсполнителя.ПустаяСсылка) ТОГДА ДанныеБизнесПроцессов.ГлавнаяЗадача.Выполнена = ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ
И ВЫБОР КОГДА НЕ ДанныеБизнесПроцессов.ГлавнаяЗадача В (ВЫБРАТЬ ВТ_ПодчиненныеЗадачи.ГлавнаяЗадача ИЗ ВТ_ПодчиненныеЗадачи КАК ВТ_ПодчиненныеЗадачи) ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ
ИЛИ &ЗадачиМнеПоказыватьНеАктуальные)
И (ЗадачиСRLS.ТекущийИсполнитель = &ТекущийПользователь
ИЛИ ЗадачиСRLS.ТекущийИсполнитель ССЫЛКА Справочник.ПолныеРоли И ЗадачиСRLS.НастройкаДелегирования = ЗНАЧЕНИЕ(Справочник.ДелегированиеПрав.ПустаяСсылка)
ИЛИ &ЗадачиМнеПоказыватьДелегированные)
;
////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК ЗадачиМнеВсего,
ЕСТЬNULL(СУММА(ВЫБОР КОГДА ЗадачиСRLS.ПринятаКИсполнению = ЛОЖЬ ТОГДА 1 ИНАЧЕ 0 КОНЕЦ), 0) КАК ЗадачиМнеНовые,
ЕСТЬNULL(СУММА(ВЫБОР КОГДА ЗадачиСRLS.СрокИсполнения = ДАТАВРЕМЯ(1, 1, 1) ТОГДА 0 КОГДА &ИспользоватьДатуИВремяВСрокахЗадач = ИСТИНА И ЗадачиСRLS.СрокИсполнения <= &ТекущаяДата ТОГДА 1 КОГДА &ИспользоватьДатуИВремяВСрокахЗадач = ЛОЖЬ И ЗадачиСRLS.СрокИсполнения < &ДатаОкончанияТекущегоДня ТОГДА 1 ИНАЧЕ 0 КОНЕЦ), 0) КАК ЗадачиМнеПросроченные,
ЕСТЬNULL(СУММА(ВЫБОР КОГДА ЗадачиСRLS.ТекущийИсполнитель ССЫЛКА Справочник.ПолныеРоли И ЗадачиСRLS.НастройкаДелегирования <> ЗНАЧЕНИЕ(Справочник.ДелегированиеПрав.ПустаяСсылка) ТОГДА 1 ИНАЧЕ 0 КОНЕЦ), 0) КАК ЗадачиМнеДелегированные
ИЗ ЗадачиСRLS КАК ЗадачиСRLS
ГДЕ (НЕ ЕСТЬNULL(ВТ_ПодчиненныеЗадачи.ЕстьПодчиненныеЗадачи, ЛОЖЬ)
И ВЫБОР КОГДА ДанныеБизнесПроцессов.ГлавнаяЗадача <> ЗНАЧЕНИЕ(Задача.ЗадачаИсполнителя.ПустаяСсылка) ТОГДА ДанныеБизнесПроцессов.ГлавнаяЗадача.Выполнена = ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ
И ВЫБОР КОГДА НЕ ДанныеБизнесПроцессов.ГлавнаяЗадача В (ВЫБРАТЬ ВТ_ПодчиненныеЗадачи.ГлавнаяЗадача ИЗ ВТ_ПодчиненныеЗадачи КАК ВТ_ПодчиненныеЗадачи) ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ
ИЛИ &ЗадачиМнеПоказыватьНеАктуальные)

Автор выявил, что проблема заключается в первой выборке запроса. Если оставить только создание временных таблиц и вторую выборку, зависания не происходит. Это ценное наблюдение, указывающее на конкретный блок кода для оптимизации.

3.1. Анализ плана запроса

План запроса — это графическое или текстовое представление того, как СУБД намеревается выполнить ваш запрос. Мы должны внимательно изучить его, чтобы найти узкие места.

  1. Интерпретация плана: В плане запроса мы ищем такие операции, как полные сканирования таблиц (Table Scan), дорогие операции соединений (Join), сортировки (Sort), а также анализируем используемые индексы и предполагаемую стоимость каждой операции. Высокая стоимость определенных шагов всегда указывает на потенциальные проблемы.
  2. Индексы: Отсутствие или неоптимальное использование индексов — частая причина медленных запросов. При анализе плана запроса следует проверять, какие индексы использует СУБД. Возможно, требуется добавить новые или изменить существующие индексы на полях, участвующих в условиях ГДЕ, СОЕДИНЕНИЕ и СГРУППИРОВАТЬ ПО.
  3. Параметризованные запросы: В 1С широко используются параметризованные запросы. СУБД кэширует планы для них. Если параметр сильно влияет на кардинальность (количество возвращаемых строк), план может быть неоптимальным для всех значений. Это может быть проблемой для нашего запроса, который выбирает данные для обновления дерева задач.

3.2. Оптимизация запросов с временными таблицами (ВТ)

В нашем запросе активно используются временные таблицы. Это мощный инструмент, но его неэффективное использование может привести к замедлениям.

  1. Индексирование ВТ: Платформа 1С по умолчанию не индексирует временные таблицы. Если мы видим, что к временным таблицам, таким как ИсполнителиЗадач, Задачи, ЗадачиСRLS, ВТ_ПредметыПоЗадачам, ВТ_ПредметыВнтуренниеДокументы, ВТ_НомерПредмета, ВТ_Предмет, идет много обращений, или они используются в условиях соединений и отборов, мы должны явно создать для них индексы. Это делается с помощью оператора ИНДЕКСИРОВАТЬ ПО в запросе. Например:
    
    ВЫБРАТЬ ИсполнителиРолейИДелегаты.РольПользователь КАК Исполнитель, ...
    ПОМЕСТИТЬ ИсполнителиЗадач
    ИЗ РегистрСведений.ИсполнителиРолейИДелегаты КАК ИсполнителиРолейИДелегаты
    ...
    ИНДЕКСИРОВАТЬ ПО Исполнитель
    ;
    
  2. Размер ВТ: Чем меньше данных во временных таблицах, тем быстрее они обрабатываются. Мы должны стремиться к максимально ранней фильтрации данных для сокращения объема ВТ. Если возможно, перенесите часть условий ГДЕ из основной выборки в создание временных таблиц.
  3. Порядок соединений: Для сложных запросов с несколькими соединениями порядок соединений может существенно влиять на производительность. Хотя СУБД обычно оптимизирует порядок, иногда явное указание порядка вложенных запросов или рефакторинг запроса может помочь.

3.3. Влияние RLS (Разграничение доступа на уровне записей)

Сообщение 2 справедливо указывает на то, что RLS может быть причиной медленного выполнения запросов. RLS, особенно при сложной настройке, может неявно добавлять в запросы дополнительные соединения и отборы, что усложняет их и увеличивает время выполнения.

  1. Дополнительные соединения: Когда активирован RLS, платформа 1С добавляет к вашему запросу дополнительные условия для проверки прав доступа к данным на уровне записей. Это может быть реализовано через дополнительные соединения с регистрами прав доступа, что значительно увеличивает сложность плана запроса.
  2. Диагностика: Если мы подозреваем RLS как причину замедления, мы можем временно отключить RLS для проблемного пользователя или конкретного объекта (в тестовой базе) и сравнить производительность. Мы также должны внимательно анализировать планы запросов, обращая особое внимание на дополнительные условия, связанные с проверкой прав, которые могли быть добавлены автоматически. В нашем запросе есть блок ПОМЕСТИТЬ ЗадачиСRLS, который явно работает с РегистрСведений.СоставСубъектовПравДоступа, что подтверждает влияние RLS.

3.4. Управление блокировками и Snapshot Isolation

Зависание интерфейса на 120 секунд, особенно когда повторный запуск того же запроса в другом сеансе также зависает, сильно наводит на мысль о проблемах с блокировками.

  1. Типы блокировок: Мы различаем пессимистические (управляемые 1С) и оптимистические (управляемые СУБД) блокировки. Синхронные попытки блокировки, упомянутые в теме, могут быть связаны с пессимистическими блокировками, когда один сеанс удерживает ресурс (например, таблицу или строку), необходимый другому сеансу.
  2. Таймауты блокировок: Длительное зависание может быть связано с таймаутом ожидания блокировки. Если запрос висит 120 секунд, это может быть не только таймаут СУБД, но и ожидание блокировки, установленной другим сеансом.
  3. Мониторинг СУБД: Внешние средства мониторинга СУБД (например, Activity Monitor в SQL Server Management Studio, профайлеры СУБД или сторонние утилиты) позволяют нам увидеть текущие блокировки, кто их установил и какие ресурсы заблокированы. Это помогает выявить «голодающие» запросы и «блокирующие» сеансы.
  4. Использование Snapshot Isolation (для MS SQL Server): Если мы работаем с MS SQL Server, включение режима изоляции снимков (Snapshot Isolation) может значительно уменьшить количество блокировок чтения. Читающие запросы в этом режиме не блокируют пишущие и наоборот. Вместо этого они работают с «снимком» данных на момент начала транзакции, что существенно повышает параллельность работы системы. Для этого нам необходимо включить ALLOW_SNAPSHOT_ISOLATION и READ_COMMITTED_SNAPSHOT для базы данных и убедиться, что приложение 1С корректно работает в этом режиме. Это может быть эффективным решением для уменьшения хаотичных зависаний, вызванных блокировками.

4. Дополнительные рекомендации по оптимизации

Помимо точечной работы с проблемным запросом, мы должны учитывать и общие рекомендации по поддержанию производительности системы.

  1. Версии платформы 1С и СУБД: Убедитесь, что используются актуальные версии платформы 1С и СУБД. Разработчики постоянно выпускают обновления с исправлениями производительности и оптимизациями.
  2. Кэширование: Проверьте эффективность кэширования данных. В нашем запросе используется регистр сведений КешИнформацииОбОбъектах. Если данные в нем устаревают или неэффективно заполняются, это может приводить к повторным дорогостоящим запросам вместо использования кэшированной информации. Мы должны проанализировать, как заполняется и используется этот кэш.
  3. Профилирование: Хотя мы хотели избежать этого на первом этапе, если все остальные методы не дают полного решения, использование встроенного в 1С профайлера («Замер производительности») или инструментов СУБД (например, SQL Server Profiler) может помочь детально отследить выполнение каждого шага запроса и выявить узкие места на уровне кода 1С и СУБД.
  4. Раннее отсечение данных: При отсутствии данных в кэше и сканировании таблиц целиком нам следует стараться наложить как можно раньше более строгие отборы. Хотя фильтр по пользователю полезен, он может возвращать очень много записей. Фильтр по списку вообще не всегда является оптимальным, и его следует использовать с осторожностью, особенно если список большой.

Выявив конкретный проблемный запрос и используя вышеописанные методы диагностики и оптимизации, мы можем существенно повысить производительность работы пользователей в 1С:Документооборот и устранить надоедливые зависания интерфейса. Системный подход и глубокий анализ плана выполнения запросов в СУБД являются ключом к успеху.

← На главную