УТ11.3
ТЖ с logcfg на длительность запросов периодически выявляет запрос к РС "Версии объектов".
Как видно из контекста - это снова стандартная подсистема "Текущие дела" (уже 3й случай неоптимальных запросов в этой подсистеме, дающих СУБД время задуматься):
// Предоставляет информацию о количестве и объеме устаревших версий объектов.
Функция ИнформацияОбУстаревшихВерсиях()
УстановитьПривилегированныйРежим(Истина);
ГраницыУдаленияОбъектов = ГраницыУдаленияОбъектов();
Запрос = Новый Запрос;
ТекстЗапроса =
"ВЫБРАТЬ
| ЕСТЬNULL(СУММА(ВерсииОбъектов.РазмерДанных), 0) КАК РазмерДанных,
| ЕСТЬNULL(СУММА(1), 0) КАК КоличествоВерсий
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
| ВерсииОбъектов.ЕстьДанныеВерсии
| И &ДополнительныеУсловия";
ДополнительныеУсловия = "";
Для Индекс = 0 По ГраницыУдаленияОбъектов.Количество() - 1 Цикл
Если Не ПустаяСтрока(ДополнительныеУсловия) Тогда
ДополнительныеУсловия = ДополнительныеУсловия + "
| ИЛИ";
КонецЕсли;
ИндексСтрокой = Формат(Индекс, "ЧН=0; ЧГ=0");
Условие = "";
Для Каждого Тип Из ГраницыУдаленияОбъектов[Индекс].СписокТипов Цикл
Если Не ПустаяСтрока(Условие) Тогда
Условие = Условие + "
| ИЛИ";
КонецЕсли;
Условие = Условие + "
| ВерсииОбъектов.Объект ССЫЛКА " + Тип;
КонецЦикла;
Если ПустаяСтрока(Условие) Тогда
Продолжить;
КонецЕсли;
Условие = "(" + Условие + ")";
ДополнительныеУсловия = ДополнительныеУсловия + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
"
| %1
| И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления%2",
Условие,
ИндексСтрокой);
Запрос.УстановитьПараметр("СписокТипов" + ИндексСтрокой, ГраницыУдаленияОбъектов[Индекс].СписокТипов);
Запрос.УстановитьПараметр("ГраницаУдаления" + ИндексСтрокой, ГраницыУдаленияОбъектов[Индекс].ГраницаУдаления);
КонецЦикла;
Если ПустаяСтрока(ДополнительныеУсловия) Тогда
ДополнительныеУсловия = "ЛОЖЬ";
Иначе
ДополнительныеУсловия = "(" + ДополнительныеУсловия + ")";
КонецЕсли;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеУсловия", ДополнительныеУсловия);
Запрос.Текст = ТекстЗапроса;
Выборка = Запрос.Выполнить().Выбрать();
КоличествоВерсий = 0;
РазмерДанных = 0;
Если Выборка.Следующий() Тогда
РазмерДанных = Выборка.РазмерДанных;
КоличествоВерсий = Выборка.КоличествоВерсий;
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("КоличествоВерсий", КоличествоВерсий);
Результат.Вставить("РазмерДанных", РазмерДанных);
Возврат Результат;
КонецФункции
Показать
Запрос на sql:
SEL ECT
ISNULL(CAST(CAST(SUM(T1._Fld18639) AS NUMERIC(21, 0)) AS NUMERIC(21, 0)),0.0),
ISNULL(CAST(CAST(SUM(1.0) AS NUMERIC(7, 0)) AS NUMERIC(7, 0)),0.0)
FR OM dbo._InfoRg13529 T1
WHERE ((T1._Fld706 = 0)) AND (T1._Fld18641 = 0x01
AND (((((((T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x000000DA)
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x000000DC))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000012C))
AND (T1._Fld13534 < '20010101 00:00:00')) OR ((T1._Fld13530_TYPE = 0x08
AND T1._Fld13530_RTRef = 0x00000056) AND (T1._Fld13534 < '40171229 07:58:50')))
OR ((((((((((((((((T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000008A)
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000117))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000118))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000011F))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000121))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000125))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000129))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000132))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000133))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000013A))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000014B))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000014C))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000155))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x00000166))
OR (T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000016F))
AND (T1._Fld13534 < '40180929 07:58:50'))) OR ((T1._Fld13530_TYPE = 0x08 AND T1._Fld13530_RTRef = 0x0000017B) AND (T1._Fld13534 < '40180629 07:58:50'))))
Показать
Так вот sql-запрос из ssms выполняется мгновенно, но "кричит" об отсутствии индекса с почти максимальным влиянием и предлагает это сделать:
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[_InfoRg13529] ([_Fld18641],[_Fld706])
INCLUDE ([_Fld13530_TYPE],[_Fld13530_RTRef],[_Fld13534],[_Fld18639])
Я решил глянуть, а что это за поле, и индексировано ли оно средствами 1с и оказалось, что все вроде бы ОК.
Так в чем же причина сего поведения? Индекс то есть, только без доп полей в INCLUDE:)
(3) Вряд ли. Ради интереса попробовал переписать запрос как рекомендуют в статье.
Было:
ВЫБРАТЬ
ЕСТЬNULL(СУММА(ВерсииОбъектов.РазмерДанных), 0) КАК РазмерДанных,
ЕСТЬNULL(СУММА(1), 0) КАК КоличествоВерсий
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ((ВерсииОбъектов.Объект ССЫЛКА Справочник.СоглашенияСКлиентами
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Справочник.СоглашенияСПоставщиками
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ЛистКассовойКниги)
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления0
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Справочник.ДоговорыКонтрагентов
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления1
ИЛИ (ВерсииОбъектов.Объект ССЫЛКА Справочник.Номенклатура
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ВозвратТоваровОтКлиента
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ВозвратТоваровПоставщику
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаданиеНаПеревозку
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаказКлиента
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаказПоставщику
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаявкаНаВозвратТоваровОтКлиента
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.КорректировкаПоступления
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.КорректировкаРеализации
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ОприходованиеИзлишковТоваров
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ПередачаТоваровМеждуОрганизациями
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ПеремещениеТоваров
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.ПоступлениеТоваровУслуг
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.РеализацияТоваровУслуг
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.СписаниеНедостачТоваров)
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ИЛИ ВерсииОбъектов.Объект ССЫЛКА Документ.УстановкаЦенНоменклатуры
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления3)
Показать
Стало:
ВЫБРАТЬ
СУММА(Версии.РазмерДанных) КАК РазмерДанных,
СУММА(Версии.КоличествоВерсий) КАК КоличествоВерсий
ИЗ
(ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных) КАК РазмерДанных,
СУММА(1) КАК КоличествоВерсий
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Справочник.СоглашенияСКлиентами
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления0
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Справочник.СоглашенияСПоставщиками
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления0
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ЛистКассовойКниги
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления0
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Справочник.ДоговорыКонтрагентов
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Справочник.Номенклатура
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ВозвратТоваровОтКлиента
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ВозвратТоваровПоставщику
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаданиеНаПеревозку
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаказКлиента
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаказПоставщику
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ЗаявкаНаВозвратТоваровОтКлиента
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.КорректировкаПоступления
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.КорректировкаРеализации
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ОприходованиеИзлишковТоваров
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ПередачаТоваровМеждуОрганизациями
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ПеремещениеТоваров
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.ПоступлениеТоваровУслуг
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.РеализацияТоваровУслуг
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.СписаниеНедостачТоваров
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
СУММА(ВерсииОбъектов.РазмерДанных),
СУММА(1)
ИЗ
РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
ГДЕ
ВерсииОбъектов.ЕстьДанныеВерсии
И ВерсииОбъектов.Объект ССЫЛКА Документ.УстановкаЦенНоменклатуры
И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления3) КАК Версии
Показать
Разница в скорости выполнения в консоли запросов - никакая. Вижу лишь разные планы выполнения.
Но и переписанный также "ругается" на недостаток индекса, правда уже большого составного)
В dm_db_missing_index_groups он также присутствует, т.е. это не какой-то одиночный запрос... это запрос из текущих дел, которые есть почти у каждого на рабочем столе!
(8) Посмотрел план запроса, есть замечания:
1. Оператор "Clustered Index Seek". Ожидаемое количество строк несколько больше, чем реально было возвращено, но это не критично, так как прочитано меньше чем было ожидаемо. Все же посмотрите статистику.
Как мне кажется основная проблема в том, что было прочитано более 2 млн строк. Из-за этого не хватило памяти выделенной на запрос и СУБД скинула таблицу в TempDB, что существенно замедлило его выполнение и скорее всего скажется на PLE.
Похоже, не смотря на то что оператор называется Seek, по факту это Scan. Так как есть только одно условие по параметру @P1 (есть подозрение что это просто разделитель) а второе условие выполняется сканированием таблицы после наложения отбора по первому параметру. В этом случае по факту СУБД сканирует таблицу целиком. Проверьте этот момент, посмотрите что за поле у вас _Fld706.
2. Во втором операторе накладывается фильтр. В целом тут нет проблем, так как условие И_ИЛИ выполняется только по одному полю, _Fld13530. Тут всё было хорошо, если бы на вход подавалось поменьше строк.
Можно попробовать выполнить запрос с подзапросом. Подзапросом вы отбираете строки с условием, а в основном запросе агрегируете.
Если ничего не поможет, то советую рассчитывать данные заранее, например регламентным заданием и сохранять их в регистре. Все таки отбор по 2.3 млн строк это прилично.
Из-за этого не хватило памяти выделенной на запрос и СУБД скинула таблицу в TempDB
Как Вы поняли, что задействована временная таблица?
Похоже, не смотря на то что оператор называется Seek, по факту это Scan
Похоже на то... "сик" лишь по _Fld706 ("ОбластьДанныхОсновныеДанные", ну, типа "разделитель"), а дальше скан по _Fld13530_TYPE, _Fld13530_RTRef, _Fld13534 и _Fld18639. Не увидел сразу.
Статистика обновляется каждую ночь.
Так прикол в том, что у меня этот запрос выполняется моментально, но бывает, что в ТЖ у кого-то всплывет. В принципе, не критично, но имеется "спортивный интерес", собственно, а почему.
(10) А у вас платформа (режим совместимости конфигурации) какая? 8.2 или 8.3?
В консоли или отладчике запрос может пройти быстро если вы его запускаете в монопольном режиме, в тестовой базе (ut_test?), где кроме вас никого нет, шаред буфер уже заполнен нужными запросу данными (прогрет). А в боевой среде в общей памяти субд может не быть нужных данных, начинается вытеснение грязных страниц. Надо найти в ТЖ 1С время выполнения этого проблемного запроса, и посмотреть счетчики этого времени на сервере SQL (Latch, PLE, Avg. Disk sec/Write, Lazy Writes/Sec).
Собственно предупреждение в запросе "operation caused residual i/o" намекает на избыточное чтение данных.
(11) Запрос выполнял в рабочей базе (в плане запроса я поменял название базы на ut_test).
Выполнял его как в самой 1с, так и в ssms.
Режим совместимости "Версия 8.3.8"
Оптимизация конечно вещь полезная. Вот только есть решение проще: отключить к х-м эту долбанную панель "Текущие дела".
Её никто не использует, а срабатывает она при входе каждого пользователя. Хоть фин.директора, хоть кладовщика. Но ни один из них ею не пользуется.