8.х Отчет формируется медленно

Тема в разделе "Конфигурирование на платформе "1С:Предприятие 8"", создана пользователем Elli, 19 июн 2008.

  1. TopicStarter Overlay
    Elli
    Offline

    Elli Опытный в 1С

    Регистрация:
    20 май 2008
    Сообщения:
    68
    Симпатии:
    0
    Баллы:
    26
    Отчет формируется медленно из-за того, что в цикле вызывается еще один запрос, номенклатуры 2500 элементов, столько раз и запрос выполняется, но не могу придумать как мне по другомы вытащить количество товара из приходного документа, или просто оптимизировать, чтобы работало быстрее
    В первом запросе по всему справочнику номенклатуры выводятся остатки и количество+сумма проданного, также определяется закупочная цена и документ, который эту цену зарегестрировал, а второй запрос вызывается для того, чтобы определить сколько товара пришло по этому документу:
    Код:
    Функция СебестоимостьДок(Док,ВыбСклад,Номенкл)
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор КАК Регистратор,
    |    ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура,
    |    ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоПриход
    |ИЗ
    |    РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты(, , Регистратор, , 
    Склад = &ВыбСклад) КАК ПартииТоваровНаСкладахОстаткиИОбороты
    |ГДЕ
    |    ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор = &Док
    |    И ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура = &Номенкл";
    
    Запрос.УстановитьПараметр("Док",Док );
    Запрос.УстановитьПараметр("ВыбСклад",ВыбСклад);
    Запрос.УстановитьПараметр("Номенкл",Номенкл);
    ТЗ = Новый ТаблицаЗначений;
    ТЗ = Запрос.Выполнить().Выгрузить();
    
    Возврат ТЗ;
    КонецФункции
    
    Процедура АнализПродаж(ТабДок, ВыбСклад, ДатаНачала, ДатаОкончания) Экспорт
    //{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ(АнализПродаж)
    // Данный фрагмент построен конструктором.
    // При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
    ПТипЦен = Справочники.ТипыЦенНоменклатуры.Закупочная;
    
    Отбор = Новый Структура;
    Отбор.Вставить("ТипЦен",ПТипЦен);
    Макет = ОтчетОбъект.ПолучитьМакет("АнализПродаж1");
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    СпрНоменклатура.Ссылка КАК Товар,
    |    СпрНоменклатура.Представление КАК Представление,
    |    ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоРасход КАК КоличествоРасход,
    |    ПартииТоваровНаСкладахОстаткиИОбороты.СтоимостьРасход КАК СтоимостьРасход,
    |    ПартииТоваровНаСкладахОстаткиИОбороты.СтоимостьКонечныйОстаток КАК СтоимостьКонечныйОстаток,
    |    ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток,
    |    ЦеныНоменклатурыСрезПоследних.Цена КАК ЦенаЗак,
    |    ЦеныНоменклатурыСрезПоследних.Регистратор КАК ДокПрих
    |ИЗ
    |    Справочник.Номенклатура КАК СпрНоменклатура
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты(&ДатаНачала, 
    &ДатаОкончания, , , Склад = &ВыбСклад) КАК ПартииТоваровНаСкладахОстаткиИОбороты
    |        ПО ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура = СпрНоменклатура.Ссылка
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаОкончания,
    ТипЦен = &ЗТипЦен) КАК ЦеныНоменклатурыСрезПоследних
    |        ПО ЦеныНоменклатурыСрезПоследних.Номенклатура = СпрНоменклатура.Ссылка
    |
    |УПОРЯДОЧИТЬ ПО
    |    СпрНоменклатура.Наименование
    |ИТОГИ
    |    СУММА(КоличествоРасход),
    |    СУММА(СтоимостьРасход),
    |    СУММА(СтоимостьКонечныйОстаток),
    |    СУММА(КоличествоКонечныйОстаток)
    |ПО
    |    Товар ИЕРАРХИЯ";
    
    Запрос.УстановитьПараметр("ВыбСклад", ВыбСклад);
    Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
    Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания));
    Запрос.УстановитьПараметр("ЗТипЦен", ПтипЦен);
    
    
    Результат = Запрос.Выполнить();
    
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьЗаголовок.Параметры.ВыбСклад = ВыбСклад;
    ОбластьЗаголовок.Параметры.ДатаНачала = ДатаНачала;
    ОбластьЗаголовок.Параметры.ДатаОкончания = ДатаОкончания;
    ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
    ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
    ОбластьПодвалТаблицы = Макет.ПолучитьОбласть("ПодвалТаблицы");
    ОбластьОбщийИтог = Макет.ПолучитьОбласть("ОбщиеИтоги");
    ОбластьТоварИерархия = Макет.ПолучитьОбласть("ТоварИерархия");
    ОбластьТовар = Макет.ПолучитьОбласть("Товар");
    
    ТабДок.Очистить();
    ТабДок.Вывести(ОбластьЗаголовок);
    ТабДок.Вывести(ОбластьШапкаТаблицы);
    
    //ВыборкаОбщийИтог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    //ВыборкаОбщийИтог.Следующий();        // Общий итог
    //ОбластьОбщийИтог.Параметры.Заполнить(ВыборкаОбщийИтог);
    //ТабДок.Вывести(ОбластьОбщийИтог);
    //ВыборкаТовар = ВыборкаОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    ВыборкаТовар = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    Пока ВыборкаТовар.Следующий() Цикл
    Уровень = ВыборкаТовар.Уровень();
    ПечКод = Прав(ВыборкаТовар.Товар.Код,4);
    Пробелы = "";
    Для Тмп = 1 По Уровень Цикл
    Пробелы = Пробелы + "    ";
    КонецЦикла;
    Если ВыборкаТовар.ТипЗаписи() = ТипЗаписиЗапроса.ИтогПоИерархии Тогда
    Область = ОбластьТоварИерархия;
    Область.Параметры.ПечКод = ПечКод;
    Область.Параметры.Представление = Пробелы + ВыборкаТовар.Представление;
    Область.Параметры.КоличествоРасход = ВыборкаТовар.КоличествоРасход;
    Область.Параметры.СтоимостьРасход = ВыборкаТовар.СтоимостьРасход;
    Область.Параметры.КоличествоКонечныйОстаток = ВыборкаТовар.КоличествоКонечныйОстаток;
    Область.Параметры.СтоимостьКонечныйОстаток = ВыборкаТовар.СтоимостьКонечныйОстаток;
    ТабДок.Вывести(Область);
    Иначе
    Если ВыборкаТовар.Товар.ЭтоГруппа Тогда
    Иначе    
    ВыборкаДетали = ВыборкаТовар.Выбрать();
    ВыборкаДетали.Следующий();
    Область = ОбластьТовар;
    ЦенаЗакуп = ВыборкаДетали.ЦенаЗак;
    НашДок = ВыборкаДетали.ДокПрих;
    Если НашДок <> NULL Тогда
    ДатаЗакуп = ВыборкаДетали.ДокПрих.Дата;
    ТС = СебестоимостьДок(НашДок,ВыбСклад,ВыборкаТовар.Товар);
    КолЗакуп = ТС.Итог("КоличествоПриход");
    Иначе    
    ДатаЗакуп = "";
    КолЗакуп = ""
    КонецЕсли;    
    Область.Параметры.КолЗакуп = КолЗакуп;
    Область.Параметры.ЦенаЗакуп = ЦенаЗакуп;
    Область.Параметры.ДатаЗакуп = ДатаЗакуп;
    Область.Параметры.ПечКод = ПечКод;
    Область.Параметры.Представление = Пробелы + ВыборкаТовар.Представление;
    Область.Параметры.КоличествоРасход = ВыборкаТовар.КоличествоРасход;
    Область.Параметры.СтоимостьРасход = ВыборкаТовар.СтоимостьРасход;
    Область.Параметры.КоличествоКонечныйОстаток = ВыборкаТовар.КоличествоКонечныйОстаток;
    Область.Параметры.СтоимостьКонечныйОстаток = ВыборкаТовар.СтоимостьКонечныйОстаток;
    ТабДок.Вывести(Область);
    КонецЕсли;
    КонецЕсли;
    КонецЦикла;
    
    ТабДок.Вывести(ОбластьПодвалТаблицы);
    ТабДок.Вывести(ОбластьПодвал);
    
    
    Профи, подскажите пожалуйста, я только начала разбираться в 8-ке, ничего в голову не приходит
  2. lazy
    Offline

    lazy Модераторы Команда форума Модератор

    Регистрация:
    1 сен 2007
    Сообщения:
    2.127
    Симпатии:
    4
    Баллы:
    29
    Самый простой метод - затащить запрос в вызывающую его процедуру. И определение запроса с текстом поставить до начала цикла, а в самом цикле только устанавливать ему параметры и вызывать запрос. Это не значительная но все же оптимизация - связанная с экономией времени на проверку корректности запроса и инициализации создании объекта.

    Но если по хорошему - нужно переписывать основной запрос.
  3. uza
    Offline

    uza 1С, VBA (EXCEL), VB (.NET + WEB)

    Регистрация:
    10 июл 2007
    Сообщения:
    1.845
    Симпатии:
    1
    Баллы:
    29
    Собственно как и в любой среде.
    Запрос не надо в цикле (на интерпритацию его в SQL затраты раз,
    на обработку SQL два, на скрытую обработку результата запроса - три,
    на передачу данных туда сюда - четыре).
    Запрос надо один раз. В качестве параметра передаешь список
    номенклатуры (или сразу табличную часть дока). Соответсвенно он тебе возвращает
    не одно значение, а набор значений. Результат запроса допустим грузишь в таблицу значений,
    и уже потом "дергаешь" нужные данные из этой таблицы. Ускорение (по крайней мере этого участка)
    в разы... если не в десятки раз.
    Во вторых, я бы пожалуй отчет построил по другому. На одном запросе все бы построил вообще.
    Сразу бы "рвал" все нужные данные запросом, а уж потом обходом запроса
    бы и собирал выходную форму.
  4. BabySG
    Offline

    BabySG Администраторы Команда форума Администратор

    Регистрация:
    10 июн 2007
    Сообщения:
    11.853
    Симпатии:
    12
    Баллы:
    29
    По порядку:
    1. За такое:
    Код:
    "
    ...
    |ГДЕ
    |    ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор = &Док
    |    И ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура = &Номенкл";
    
    Бьют по рукам... Линейкой.... Больно...

    2.
    Код:
    ПечКод = Прав(ВыборкаТовар.Товар.Код,4);
    
    что мешает вытащить сразу в запросе код товара? А то каждый раз к базе ломитесь и читаете весь объект.

    3.
    Код:
    Если ВыборкаТовар.Товар.ЭтоГруппа Тогда
    Иначе    
    
    Это тоже какое-то ноу-хау. В запросе можно фильтр сделат

    4. Полностью надо код переписать - запрос должен быть один.
  5. TopicStarter Overlay
    Elli
    Offline

    Elli Опытный в 1С

    Регистрация:
    20 май 2008
    Сообщения:
    68
    Симпатии:
    0
    Баллы:
    26
    Я поняла, что надо переписать запрос так, чтобы он один остался, но не пойму как вытащить из регистратора из СрезПослединих номенклатуру и количество. Как это можно объединить в один запрос?
    :unsure:
  6. BabySG
    Offline

    BabySG Администраторы Команда форума Администратор

    Регистрация:
    10 июн 2007
    Сообщения:
    11.853
    Симпатии:
    12
    Баллы:
    29
    "второй запрос вызывается для того, чтобы определить сколько товара пришло по этому документу"
    Так и ломись к реальной таблице - зачем к виртуальной-то?

    Левое соединение и все.
  7. TopicStarter Overlay
    Elli
    Offline

    Elli Опытный в 1С

    Регистрация:
    20 май 2008
    Сообщения:
    68
    Симпатии:
    0
    Баллы:
    26
    Товар может прийти по разным документам: ПоступлениеТоваров, ОприходованиеТМЦ и т.д., не пойму я как можно сделать одним запросом. Вопрос очень актуален для меня, т.к. на работе отчет формируется в несколько раз медленнее чем дома, подскажите пожалуйста, приведите пример.
  8. AlexFF
    Offline

    AlexFF Разбирающийся

    Регистрация:
    6 мар 2007
    Сообщения:
    565
    Симпатии:
    1
    Баллы:
    26
    Что-то мне подсказывает, что у любого документа оприходования в обязательном порядке есть табличная часть "Товары" а в ней в обязательно порядке реквизит "Количество". Вопрос, а зачем мне тогда знать вид документа оприходования?

    Код:
    ДокПрих.Товары
    
    Наверное как-то вот так можно попробовать.

Поделиться этой страницей