ОПИСАНИЕ ПРОБЛЕМЫ
УТ 2.3.2.6 для Украины, но и в российской версии так же присутствует проблемный запрос.
Платформа 8.1.12.101, MS SQL Server 2005, Windows Server 2003 R2 Enterprise x64 Edition SP2
Компьютер: Intel® Xeon® CPU E5430 @ 2.66GHz, 7.99GB ОЗУ
Рекомендации по регламентным операциям для MS SQL Server выполнены:
• Обновление статистик
• Очистка процедурного КЭШа
• Дефрагментация индексов
• Реиндексация таблиц базы данных
В параметрах учетной политики стоит флаг "Списывать партии при проведении документов".
Снятие его решает проблему медленного проведения документа, но не решает проблемы медленного восстановления последовательности по партиям.
Регистры накопления рассчитаны на 31.12.2008
Проводится документ перемещения товаров от 01.10.2007 . Количество строк 546.
Замер производительности показал, что проведение в клиент-серверном варианте
в 2,67!!! раз выполняется дольше, чем в файловом.
Файловый вариант:
ОбщийМодуль.ОбщегоНазначения СтрокаДвижения.НаборЗаписей.Записать(); - 31,542450 сек
ОбщийМодуль.УправлениеЗапасамиПартионныйУчет Возврат Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) - 30,270411 сек
Клиент - серверный вариант:
ОбщийМодуль.ОбщегоНазначения СтрокаДвижения.НаборЗаписей.Записать(); - 5,217208 сек ОбщийМодуль.УправлениеЗапасамиПартионныйУчет Возврат Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - 160,466609 сек
Исследование проведения документа в парсере SQL показали что бульшую часть времени уходит на выполнение запроса, сформированного в 1С. Формируется этото запрос в процедуре ЗаполнитьЗапросПартийНаСкладахУпр общего модуля УправлениеЗапасамиПартионныйУчет.
там есть участок:
|ИЗ
| РегистрСведений.СписанныеТовары КАК СписанныеТовары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ПартииТоваровНаСкладах.Остатки(
| &Дат,
| Номенклатура В
| (ВЫБРАТЬ
| РегистрСведений.СписанныеТовары.Номенклатура
| ИЗ
| РегистрСведений.СписанныеТовары
| ГДЕ
| РегистрСведений.СписанныеТовары.Регистратор = &Ссылка)"
+ ?(ВестиПартионныйУчетПоСкладам, "
| И (Склад В
| (ВЫБРАТЬ
| РегистрСведений.СписанныеТовары.Склад
| ИЗ
| РегистрСведений.СписанныеТовары
| ГДЕ
| РегистрСведений.СписанныеТовары.Регистратор = &Ссылка)
| ИЛИ Склад = &ПустойСклад)", "") + ") КАК ПартииТоваровНаСкладах
проанализровав который, сдел вывод, что для каждой строки партии выполняется запрос для получения списка номенклатуры из регистра сведений СписанныеТовары. А теперь представим что строк в документе более 500 и регистр Списанныетовары сам по себе огромный, то колличество таких внутренних "одних и тех же" запросов прямопропорцинально количеству строк в документе регистраторе. Вобщем SQL-ю стало плохо о такого условия с выборкой.
Что сделал я. Сначала с помощью вложенных запросов получил списки необходимой номенклатуры и складов, а потом поставил в условие проверку вхождения номенклатуры и складов в полученные с помощью вложенных запросов списки.
Таким образом запрос по регистру сведений СписанныТовары выполняется один раз, а номенклатура и склад проверяются на вхождение в уже сформированные списки.
Результаты замера производительности просто потрясли: теперь
Возврат Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам)
выполняется меньше чем за 10 секунд против 160 в типовом запросе.Ответ 1С по поводу такого поведения платформы:
Спасибо за сообщение. Информация передана в отдел разработки.
Зарегистрирована ошибка 10009845
ПРЕДПОЛАГАЕМЫЙ ДИАГНОЗ
Скорее всего конструкции вида :
"
| Номенклатура В
| (ВЫБРАТЬ
| РегистрСведений.СписанныеТовары.Номенклатура
| ИЗ
| РегистрСведений.СписанныеТовары
| ГДЕ
| РегистрСведений.СписанныеТовары.Регистратор = &Ссылка)"
представляют проблему для оптимизатора MS SQL 2005.
ИСПРАВЛЕНИЕ ЗАПРОСА (ВРЕМЕННАЯ ЗАПЛАТКА, ПОКА ОШИБКА НЕ ИСПРАВЛЕНА)
Вот код измененной процедуры:
Процедура ЗаполнитьЗапросПартийНаСкладахУпр(Запрос, ВестиПартионныйУчетПоСкладам,
СтратегияСтатусПартии, СпособОценкиМПЗ)
Запрос.Текст ="
|ВЫБРАТЬ
| СписанныеТовары.НомерСтрокиДокумента КАК НомерСтрокиДокумента,
| ПартииТоваровНаСкладах.Номенклатура,
| ПартииТоваровНаСкладах.ДокументОприходования КАК ДокументОприходования,
| ПартииТоваровНаСкладах.ДокументОприходования.Дата КАК ДокументОприходованияДата,
| ПартииТоваровНаСкладах.Склад,
| ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
| ПартииТоваровНаСкладах.СерияНоменклатуры,
| ПартииТоваровНаСкладах.Качество,
| ПартииТоваровНаСкладах.Заказ,
| ПартииТоваровНаСкладах.КоличествоОстаток КАК Количество,
| ПартииТоваровНаСкладах.СтоимостьОстаток КАК Стоимость,
| ПартииТоваровНаСкладах.СтатусПартии,
| ВЫБОР
| КОГДА СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры
| ТОГДА 0
| ИНАЧЕ 1
| КОНЕЦ КАК ЧислоСерияНоменклатуры,
| ВЫБОР
| КОГДА СписанныеТовары.ДокументПартии = НЕОПРЕДЕЛЕНО
| ТОГДА 0
| ИНАЧЕ ВЫБОР
| КОГДА СписанныеТовары.ДокументПартии = ПартииТоваровНаСкладах.ДокументОприходования
| ТОГДА 0
| ИНАЧЕ 1
| КОНЕЦ
| КОНЕЦ КАК ЧислоДокументОприходования,
| ВЫБОР
| КОГДА СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО
| ТОГДА 0
| ИНАЧЕ ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ
| КОНЕЦ КАК ЧислоЗаказ,
| ВЫБОР
| КОГДА ПартииТоваровНаСкладах.СтатусПартии = &НаКомиссию
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ КАК ЧислоСтатусПартии
|ИЗ
| РегистрСведений.СписанныеТовары КАК СписанныеТовары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ПартииТоваровНаСкладах.Остатки(&Дат, ) КАК ПартииТоваровНаСкладах
| ПО СписанныеТовары.Номенклатура = ПартииТоваровНаСкладах.Номенклатура
| И СписанныеТовары.ХарактеристикаНоменклатуры = ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры
| И (ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Качество = &ПустоеКачество
| ТОГДА ИСТИНА
| ИНАЧЕ ВЫБОР
| КОГДА СписанныеТовары.Качество = &ПустоеКачество
| ТОГДА ПартииТоваровНаСкладах.Качество = &КачествоНовый
| ИНАЧЕ ПартииТоваровНаСкладах.Качество = СписанныеТовары.Качество
| КОНЕЦ
| КОНЕЦ)
| И (ПартииТоваровНаСкладах.Склад = СписанныеТовары.Склад
| ИЛИ ПартииТоваровНаСкладах.Склад = &ПустойСклад)
| И (ВЫБОР
| КОГДА СписанныеТовары.ДопустимыйСтатус1 <> &ПустойСтатус
| ИЛИ СписанныеТовары.ДопустимыйСтатус2 <> &ПустойСтатус
| ИЛИ СписанныеТовары.ДопустимыйСтатус3 <> &ПустойСтатус
| ИЛИ СписанныеТовары.ДопустимыйСтатус4 <> &ПустойСтатус
| ТОГДА ПартииТоваровНаСкладах.СтатусПартии = &ПустойСтатус
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = &СтатусПартииПоОрдеру
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус1
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус2
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус3
| ИЛИ ПартииТоваровНаСкладах.СтатусПартии = СписанныеТовары.ДопустимыйСтатус4
| ИНАЧЕ ИСТИНА
| КОНЕЦ)
| И (ВЫБОР
| КОГДА СписанныеТовары.СписыватьТолькоПоЗаказу = ИСТИНА
| ТОГДА ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии
| ТОГДА ВЫБОР
| КОГДА (НЕ СписанныеТовары.ЗаказПартии = НЕОПРЕДЕЛЕНО)
| ТОГДА ЛОЖЬ
| ИНАЧЕ ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
| КОНЕЦ
| ИНАЧЕ ИСТИНА
| КОНЕЦ
| ИНАЧЕ ВЫБОР
| КОГДА ПартииТоваровНаСкладах.Заказ <> СписанныеТовары.ЗаказПартии
| ТОГДА ПартииТоваровНаСкладах.Заказ = &ПустойЗаказ
| ИНАЧЕ ИСТИНА
| КОНЕЦ
| КОНЕЦ)
| И (СписанныеТовары.СерияНоменклатуры = ПартииТоваровНаСкладах.СерияНоменклатуры
| ИЛИ ПартииТоваровНаСкладах.СерияНоменклатуры = &ПустаяСерияНоменклатуры
| ИЛИ СписанныеТовары.КодОперацииПартииТоваров = &КодРезервирование),
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| СписанныеТовары.Номенклатура КАК Номенклатура
| ИЗ
| РегистрСведений.СписанныеТовары КАК СписанныеТовары
| ГДЕ
| СписанныеТовары.Регистратор = &Ссылка) КАК СписокТоваров,
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| СписанныеТовары.Склад КАК Склад
| ИЗ
| РегистрСведений.СписанныеТовары КАК СписанныеТовары
| ГДЕ
| СписанныеТовары.Регистратор = &Ссылка) КАК СписокСкладов
|ГДЕ
| СписанныеТовары.Регистратор = &ОсновнойДокумент
| И ПартииТоваровНаСкладах.Номенклатура В (СписокТоваров.Номенклатура)"
+?(ВестиПартионныйУчетПоСкладам, "
| И (ПартииТоваровНаСкладах.Склад В (СписокСкладов.Склад)
| ИЛИ ПартииТоваровНаСкладах.Склад = &ПустойСклад)","")+"
|
|УПОРЯДОЧИТЬ ПО
| ЧислоСерияНоменклатуры,
| ЧислоДокументОприходования,
| ЧислоЗаказ,
| ЧислоСтатусПартии" +
?(СтратегияСтатусПартии = Перечисления.СтретегииСписанияПартийТоваровПоСтатусам.СначалаПринятыеПотомСобств
енные, " Убыв", "") + ",
| ДокументОприходованияДата" + ?(СпособОценкиМПЗ = "ЛИФО", " Убыв","") + ",
| ДокументОприходования" + ?(СпособОценкиМПЗ = "ЛИФО", " Убыв","") + "
|ИТОГИ ПО
| НомерСтрокиДокумента
|";
КонецПроцедуры // ЗаполнитьЗапросПартийНаСкладахУпр()
Тестирование на типовой конигурации: выполнил полное перепроведение документов в типовой до изменения и полное перепроведение после изменения. Отчеты по партиям, по остаткам до и после СОВПАЛИ.
Рекомендуется при исправлении запроса использовать не вложенные запросы, а временную таблицу (в пакете). Сильная вложенность тоже иногда даёт непредсказуемые результаты, особенно если регламентные процедуры на сервере не проводятся.
Но на использование временных таблиц я запрос не переделывал